От новичка до гуру: Курсы программирования на CyberDuff

Запрос не возвращает результата (Delphi, Oracle, DBExpress)

Я пытаюсь получить результат запроса от сервера Oracle sql и вставить его в таблицу StringGridShowPapers.

У меня установлен и работает SQLConnection1 (соединение DBExpress), SQLDataSetPapers DataSet и запрос SQLQueryPapers.

Когда я запускаю эту процедуру, кажется, что запрос ничего не возвращает:

procedure TFormOperator.TabSheetShowPapersShow(Sender: TObject);
begin
    SQLQueryShowPapers.SQL.Text := 'SELECT * FROM papers';
    SQLQueryShowPapers.Open;
    SQLQueryShowPapers.First;

    if (NOT SQLQueryShowPapers.IsEmpty) then begin
        SQLQueryShowPapers.First;
        StringGridShowPapers.RowCount := 2;

        while (NOT SQLQueryShowPapers.EOF) do begin
            if (SQLQueryShowPapers.Fields[2].AsString = Frame11.ID) then begin
                with StringGridShowPapers do begin
                  Cells[0, (StringGridShowPapers.RowCount - 1)] :=
                    SQLQueryShowPapers.Fields[0].AsString;
                  Cells[1, (StringGridShowPapers.RowCount - 1)] :=
                    SQLQueryShowPapers.Fields[1].AsString;
                  Cells[2, (StringGridShowPapers.RowCount - 1)] :=
                    SQLQueryShowPapers.Fields[2].AsString;
                end;
                SQLQueryShowPapers.Next;
                StringGridShowPapers.RowCount := StringGridShowPapers.RowCount + 1;
            end;
        end;
    end;

end;

Frame11.ID содержит строковое значение числа.

Выполнение того же запроса SELECT * FROM papers в Oracle SQL Developer приводит к ряду строк.

Что могло вызвать проблему?

Заранее спасибо!

Похоже, я нашел решение:

Похоже, что некоторые (глобальные) переменные и свойства в Delphi недоступны или просто очищаются после завершения процедуры, которая их назначает. Таким образом, вам может потребоваться присвоить первое значение формы глобальной переменной второй (в которой вы используете это значение) во время выполнения первой процедуры формы.


  • SQLQueryShowPapers.Next; находится внутри IF BEGIN... END. вам нужно переместить его из IF 08.07.2017
  • @are спасибо, что заметили это! Но проблема все равно не ушла 08.07.2017
  • Я даже не вхожу в первое состояние 08.07.2017
  • IsEmpty когда-то был глючным. Вы можете использовать if not (Query.Bof and Query.Eof) then. Кроме того, переместите этот Next вызов за пределы блока if и удалите оба First вызова. 08.07.2017
  • @Victoria, спасибо, я поменял кондоминиум, но проблема все еще существует 08.07.2017
  • Если вы получаете ноль строк, это означает, что у вас нет строк, соответствующих Frame11.ID. Из любой используемой вами утилиты запросов запустите SELECT * FROM papers WHERE <youridfield> = '<Frame11IDValue>' и посмотрите, получите ли вы строки. (Очевидно, замените <youridfield> именем столбца, на который вы ссылаетесь, на Fields[0] в своем коде, а <Frame11IDValue> на строковое значение Frame11.ID из вашего кода.) 08.07.2017
  • Хорошо, похоже, что некоторые (глобальные) переменные и свойства в Delphi недоступны или просто очищаются после завершения процедуры, которая их назначает. Таким образом, вам может потребоваться присвоить первое значение формы глобальной переменной второй (в которой вы используете это значение) во время выполнения первой процедуры формы. 08.07.2017

Ответы:


1

В вашем коде есть пара недостатков.

Во-первых, вам не нужен IsEmpty, и вам не нужен ни один вызов First. Когда вы впервые открываете запрос, набор данных автоматически устанавливается в первой строке, и вы можете опустить IsEmpty, если знаете, что собираетесь перебирать строки.

Во-вторых, никогда не SELECT без предложения WHERE, а затем фильтровать данные. Единственная причина использовать SELECT без WHERE - это если вы абсолютно уверены, что вам нужна каждая строка (и столбец) из таблицы. Если вы этого не сделаете, добавьте WHERE, чтобы ограничить количество строк, возвращаемых сервером (и избежать необходимости писать так много кода для его фильтрации на стороне клиента).

Попробуйте вместо этого что-нибудь подобное. Я не знаю, что такое тип данных Fields[2] или Frame11.ID, поэтому я буду рассматривать их как string, как это делает ваш существующий код. Если это не строки, измените обе ссылки на фактический необходимый тип данных. Я также собираюсь предположить, что Fields[2].FieldName равно ID; опять же, если это не так, измените код соответствующим образом.

procedure TFormOperator.TabSheetShowPapersShow(Sender: TObject);
var
  GridRow: Integer;
begin
  SQLQueryShowPapers.SQL.Text := 'SELECT * FROM papers WHERE ID = :ID';
  SQLQueryShowPapers.Parameters.ParamByName('ID').Value := Frame11.ID;
  SQLQueryShowPapers.Open;  // No need for First. Happens automatically

  StringGridShowPapers.RowCount := 1;

  // No need for IsEmpty. If no rows were returned, this loop will not be entered
  while not SQLQueryShowPapers.EOF do
  begin
    StringGridShowPapers.RowCount := StringGridShowPapers.RowCount + 1;
    GridRow := StringGridShowPapers.RowCount - 1;

    StringGridShowPapers.Cells[0, GridRow] := SQLQueryShowPapers.Fields[0].AsString;
    StringGridShowPapers.Cells[1, GridRow] := SQLQueryShowPapers.Fields[1].AsString;
    StringGridShowPapers.Cells[2, GridRow] := SQLQueryShowPapers.Fields[2].AsString;
    SQLQueryShowPapers.Next;
  end;
end;

Кроме того, я бы сделал пару вещей:

  • Самое главное, прекратите использовать SELECT * и фактически перечислите нужные столбцы. Код легче поддерживать, и это снижает накладные расходы на перемещение данных с сервера по сети, которые вы не собираетесь использовать.

  • Также прекратите использовать жестко запрограммированные ссылки на позиции полей (Fields[0], Fields[1] и т. Д.). Он подвержен ошибкам, он укусит вас сзади, когда столбец изменится в будущем, и это делает невозможным поддержание кода через 6 месяцев, когда вы не помните точно, в каком порядке столбцы находятся, или кому-то еще нужно работать с вашим кодом. Либо добавьте в запрос постоянные поля, либо используйте FieldByName, чтобы получить их по имени.

  • Сократите имена переменных, чтобы не печатать. SQLQueryShowPapers, например, может быть просто QryPapers (если у вас нет другого типа запроса, кроме SQL-запроса), а StringGridShowPapers может быть GridPapers или PaperGrid.

  • Вы заметите, что я добавил локальную целочисленную переменную GridRow, чтобы уменьшить набор текста, необходимый для всех повторных вызовов, до StringGridShowPapers.RowCount - 1 при каждом доступе к Cells.

  • Вы также заметите, что я упростил добавление новых строк в StringGridShowPapers в цикле.

  • Я также устранил необходимость тестирования Fields[0].AsString = Frame11.ID, добавив параметр и предложение WHERE в ваш оператор SQL. Это также уменьшает объем данных, которые должны передаваться с сервера по сети, снижает требования к памяти вашего приложения и сокращает количество времени, которое вы тратите без необходимости на чтение строк, которые вы не будете использовать, и их пропуск (итерации через петля). Другими словами, я удалил весь if тест.

  • Наконец, вы можете сократить весь этот код до трех строк (установка SQL.Text, присвоение значения параметру и открытие запроса), если вы полностью избавились от TStringGrid и использовали вместо него TDBGrid. Он специально разработан для отображения данных из набора данных. Все, что вы делаете, - это добавляете TDBGrid в свою форму вместо TStringGrid, также отбрасываете TDataSource, подключаете TDBGrid.DataSource to theTDataSourceand theTDataSource.DataSet` к вашему запросу. Затем откройте свой запрос как обычно, и сетка автоматически заполнится данными без строк кода.

08.07.2017
  • Спасибо за советы!) Сделаю так 08.07.2017

  • 2

    попробуйте это, оператор next находится вне блока if Я думаю, что что-то в ваших данных не позволяет завершить цикл

    procedure TFormOperator.TabSheetShowPapersShow(Sender: TObject);
    begin
        SQLQueryShowPapers.SQL.Text := 'SELECT * FROM papers';
        SQLQueryShowPapers.Open;
        SQLQueryShowPapers.First;
    
        if (NOT SQLQueryShowPapers.IsEmpty) then begin
            SQLQueryShowPapers.First;
            StringGridShowPapers.RowCount := 2;
    
            while (NOT SQLQueryShowPapers.EOF) do begin
                if (SQLQueryShowPapers.Fields[2].AsString = Frame11.ID) then begin
                    with StringGridShowPapers do begin
                      Cells[0, (StringGridShowPapers.RowCount - 1)] :=
                        SQLQueryShowPapers.Fields[0].AsString;
                      Cells[1, (StringGridShowPapers.RowCount - 1)] :=
                        SQLQueryShowPapers.Fields[1].AsString;
                      Cells[2, (StringGridShowPapers.RowCount - 1)] :=
                        SQLQueryShowPapers.Fields[2].AsString;
                    end;
                    StringGridShowPapers.RowCount := StringGridShowPapers.RowCount + 1;
                end;
                 SQLQueryShowPapers.Next;
            end;
        end;
    
    end;
    
    08.07.2017
  • сделал это, все тот же пустой вывод запроса 08.07.2017
  • Новые материалы

    Представляем Narwhal Technologies (Nrwl)
    6 декабря 2016 г. Маунтин-Вью, Калифорния С тех пор, как Виктор Савкин и я (Джефф Кросс) присоединились к команде Angular в Google на заре Angular 1, Angular продемонстрировал феноменальный..

    Путь AWS  — «Изучение машинного обучения — 10 начинающих ИИ и машинного обучения на AWS».
    Универсальный ресурсный центр для изучения искусственного интеллекта и машинного обучения. НОЛЬ или ГЕРОЙ, начните свое путешествие здесь. Получите решения и пройдите обучение у экспертов AWS...

    5 простых концепций Python, ставших сложными
    #заранее извините 1) Переменные x = 4 y = 5 Переменная в Python — это символическое представление объекта. После присвоения некоторого объекта переменной Python мы приобретаем..

    «Освоение вероятности: изучение совместной, предельной, условной вероятности и теоремы Байеса —…
    Виды вероятности: Совместная вероятность Предельная вероятность Условная вероятность Диаграмма Венна в вероятностях: В “Set Theory” мы создаем диаграмму Венна...

    Основы Spring: Bean-компоненты, контейнер и внедрение зависимостей
    Как лего может помочь нашему пониманию Когда мы начинаем использовать Spring, нам бросают много терминов, и может быть трудно понять, что они все означают. Итак, мы разберем основы и будем..

    Отслеживание состояния с течением времени с дифференцированием снимков
    Время от времени что-то происходит и революционизирует часть моего рабочего процесса разработки. Что-то более забавное вместо типичного утомительного и утомительного процесса разработки. В..

    Я предполагаю, что вы имеете в виду методы обработки категориальных данных.
    Я предполагаю, что вы имеете в виду методы обработки категориальных данных. Пожалуйста, проверьте мой пост Инструментарий специалиста по данным для кодирования категориальных переменных в..