查询返回无结果(Delphi,Oracle,DBExpress)

时间:2017-07-08 11:53:11

标签: sql oracle delphi oracle-sqldeveloper dbexpress

我试图从Oracle sql server获取查询结果并将其插入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包含数字的字符串值。

在oracle SQL Developer中运行相同的查询SELECT * FROM papers会产生许多行。

什么可能引发问题?

提前致谢!

看起来我找到了解决方案

看起来Delphi中的某些(全局)变量和属性是不可访问的,或者只是在完成分配它们的过程后清理它们。因此,您可能需要在第一个表单过程的运行时将第一个表单值分配给第二个表单值(您使用此值)的全局变量。

2 个答案:

答案 0 :(得分:3)

您的代码中存在一些缺陷。

首先,您不需要IsEmpty,也不需要调用First。首次打开查询时,数据集会自动设置在第一行,如果您知道要迭代行,则可以省略IsEmpty

其次,如果没有SELECT子句,则不应WHERE,然后再过滤数据。 SELECT没有WHERE的唯一原因是,如果您完全确定需要表中的每一行(和列)。如果不这样做,请添加WHERE以限制从服务器返回的行数(并避免编写如此多的代码以在客户端进行过滤)。

尝试这样的事情。我不知道Fields[2]Frame11.ID是什么数据类型,因此我将把它们视为现有代码的string。如果它们不是字符串,则将两个引用更改为所需的实际数据类型。我也假设Fields[2].FieldNameID;再次,如果不是,请相应地更改代码。

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或{ {1}}。

  • 您会注意到我添加了一个本地整数变量PaperGrid,以减少每次访问GridRow时对StringGridShowPapers.RowCount - 1所有重复调用所需的输入。

  • 您还会注意到我更容易处理在循环中向Cells添加新行。

  • 我还删除了通过在SQL语句中添加参数和StringGridShowPapers子句来测试Fields[0].AsString = Frame11.ID的必要性。它还减少了必须通过网络从服务器传递的数据量,减少了应用程序的内存需求,并减少了不必要地读取您将不使用的行并跳过它们的时间(迭代通过环)。换句话说,我删除了整个WHERE测试。

  • 最后,如果完全删除if,可以将整个代码减少到三行(设置SQL.Text,为参数赋值,然后打开查询)使用TStringGrid代替。它专门用于显示数据集中的数据。您所做的就是将TDBGrid添加到表单中代替TDBGrid,同时删除TStringGrid,连接TDataSource TDataSource TDBGrid.DataSource to the TDataSource.DataSet `到您的查询。然后像往常一样打开查询,网格会自动填充零行代码的数据。

答案 1 :(得分:0)

试试这个,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;