Delphi TSQLDataSet没有输出SQL内连接查询

时间:2013-05-31 11:31:32

标签: sql-server delphi inner-join delphi-xe4

我正在使用TSQLConnection和TSQLDataSet从Delphi应用程序查询SQL Server(2012)数据库。到目前为止我的所有查询都运行正常,但我现在正在尝试使用INNER JOIN编写SELECT查询,并且我无法访问TSQLDataSet的任何输出。

代码:

Query_text:='SELECT Table1.Price
            'FROM [Table1]
              'INNER JOIN [Table2]
              'ON Table1.Code_ID = Table2.ID'   
            'WHERE (Table2.Code = '+QuotedStr(Temp_code)+')';

SQL_dataset.CommandType:=ctQuery; 
SQL_dataset.CommandText:=Query_text;
SQL_dataset.Open;  

If SQL_dataset.RecordCount>0 then .... { THIS RETURNS NOTHING }

如果我将此查询输入SSMS,则返回正确的信息。在我使用的所有其他SELECT查询(没有INNER JOIN)中,SQL_dataset按预期返回记录计数和字段名。

关于问题是什么以及如何解决它的任何想法?

更新:

我在TSQLDataset.RecordCount上的信息:

http://docwiki.embarcadero.com/Libraries/XE4/en/Data.SqlExpr.TCustomSQLDataSet.RecordCount

由此我没有得到一个简单的查询无法使用的印象 - 到目前为止,我已成功使用它简单的SELECT查询作为查询是否返回任何数据的标志...我只是幸运?但是,上面的链接指出它不能用于参数化查询和多表连接,所以这似乎解释了我原来的问题!非常感谢你指出我正确的方向。

此链接表明如果Bof和Eof都为true,则结果集为空:

http://docwiki.embarcadero.com/Libraries/XE4/en/Data.DB.TDataSet.Eof

If SQL_dataset.Bof=True and SQL_dataset.Eof=True then  
begin 
  Found:=False;

这是一个更好的选择吗?

更新2:

感谢您的解释,这对我来说已经开始变得有意义了。我删除了对RecordCount的所有引用,并按照建议替换为TSQLDataset.isEmpty(我完全错过了该方法,谢谢)。

我原以为只要你调用TSQLDataset.Open就会填充TSQLDataset.RecordCount,但是如果我理解正确的话不是这样的话吗?

有时我会按如下方式滚动搜索结果:

SQL_dataset.CommandType:=ctQuery; 
SQL_dataset.CommandText:=Query_text;
SQL_dataset.Open;

If SQL_dataset.IsEmpty=False then 
begin
  SQL_dataset.First;

  While not SQL_dataset.Eof do  
  begin
    { DO SOMETHING }
    SQL_dataset.Next;
  end;
end;

这显然会调用TSQLDataset.Next,所以我假设这会完成你所谈论的所有内存缓冲(根据RecordCount)。这到底发生了什么?

1 个答案:

答案 0 :(得分:0)

这是文件的代码,如DBF和CSV,而不是SQL远程数据集。

1)不保证RecordCount包含除本地文件之外的任何有用信息。如果它 - 它意味着所有数据都从mremote服务器读取到本地客户端内存。为SQL调用RecordsCount意味着"我希望我的应用程序冻结一小时,直到所有数据库内容都从服务器提取到客户端,然后因内存不足而崩溃。错误&#34 ;.使用属性.Empty.BOF.EOF

实际上,你从哪里得到RecordCount ???当您阅读文档时,您确实看到文档明确指出RecordCount与数据库中的记录数不对应,因此检查RecordCount> 0对数据库数据一无所知。
 http://docwiki.embarcadero.com/Libraries/XE4/en/Data.DB.TDataSet.RecordCount

2)使用参数。

试试这样:

with SQL_dataset do begin
     Close;
     CommandType := ctQuery;
     ParamCheck := true;
     CommandText := 'SELECT Table1.Price FROM "Table1"  ' +
          'INNER JOIN "Table2" ON Table1.Code_ID = Table2.ID  '   +
          'WHERE Table2.Code = :Temp_code ';
     Params[0].AsString := 'abcdefgh';
     Open;

     if not IsEmpty then begin
....
     end;
end;

另外,请编辑问题的标签并指定Delphi版本并指定数据库访问驱动程序


<强>更新

关于

if SQL_dataset.Bof=True and SQL_dataset.Eof=True then  
begin 
  Found:=False;

这可以写得更简单。

Found := not (SQL_dataset.Bof and SQL_dataset.Eof)

或现代德尔福

Found := not SQL_dataset.IsEmpty;

http://docwiki.embarcadero.com/Libraries/XE4/en/Data.DB.TDataSet.IsEmpty


关于没有得到印象,它不适用于简单的查询

您无法可靠地告诉复杂的查询。如果XXX是存储过程或VIEW或表,其中某些列是通过子查询计算的虚拟数据,则SELECT * FROM XXX可能是非常复杂的查询。

同时重读我上面写的内容。获取最终记录数意味着服务器应该执行查询到最后。并且网络应该将所有数据传输到最后。并且TDataSet应该将所有收到的数据缓存到内存中,以便您可以调用.Next

想象一下对一个简单表的简单查询,该表包含10M行,每行1000个字节(如名称+客户端照片) - 总共接近10 GB。考虑典型的100 Mb / s(约10 MB / s)网络。转移所有数据只是为了了解他们的数量需要多长时间?在大约2Gb转移你的32位应用程序将死于内存不足的错误。 当你真正想知道是否至少有一行或没有一行时,所有这些都会加载。

更新2

AS。在.IsEmpty之前检查while ... EOF似乎对我来说有点过度工程。在这些情况下,当数据集实际上是空的时,循环将退出w / o无论如何进入迭代体。所以,就个人而言,如果你没有带有空数据集特定代码路径的else-branch,那么可以删除这样的循环之前的检查。

至于缓存......这很难确定。通常有一个链: database file -> database server + query -> db access library -> TDataSet -> Grid or other consumer

在每个箭头处,某些缓存可能会也可能不会发生。

然后是单向和双向SQL查询/游标。 对于双向,您可以无论如何都可以.Next.Prior。这对网格很有用。但是对于服务器而言,这意味着它要么缓存所有内部行ID,直到光标(查询)关闭,或者引擎和索引自然允许在两个方向上继续查询。我敢打赌,DB服务器的数据结构和算法的自然优化选择选择了以前的方法。至少我不会考虑将后者视为可靠的隐含假设。

如果TDataSet也是单向的,或者如果TDataSet和底层库+服务器都是双向的,那么TDataSet会以小块的形式缓存数据。我估计它有十几行。它将创建额外的冗余网络往返,将每行作为单独的请求获取。但是,在网络(因此 - 延迟)上获取数百或数千也是不必要的负担。

TDbGrid通常不会自我缓存,而是将TDataSet的BufferCount(未记录,请参阅Joanna Carter的资料或文章)设置为所需的可见行数加上一些重叠以便于滚动。但是,像QuantumGrid这样的一些高级组件会实现自己的内部缓存。

因此,当您将长查询直接放入某个Grid时,用户会滚动到底部,很可能会导致延迟甚至内存耗尽。 OTOH,如果您的代码就像while循环,并且您设法将查询设置为单向(具体如何发信号通知这属于具体的库和数据集),这将为所有链提供优化内存消耗和缓存的方法性能。当然&#34;提供&#34;并不意味着所有的链实际上都实现了这一点。当然,您无法拨打.Prior.First.Locate等电话。

这些是一般性观察,您必须自己明智地判断这可能对您的系统造成多大影响。

当您处理大量(或可能很大)数据时,没有灵丹妙药。这就是为什么SQL被设计为尽可能少地从服务器传输数据,在远程端进行所有过滤。更重要的是,当逻辑上统一的数据库被分成几个实际的服务器时,WWW潮流强调了分片或聚类的概念,以保持内存需求的合理性。