2

我有一个 tquery(通过 BDE 或 BDE 仿真组件),用于选择单个记录或所有记录。

传统上,这是这样做的:

select * from clients where (clientid = :clientid or :clientid = -1) 

然后,当他们希望查询返回所有值时,他们会在字段中输入 -1。不过,通过这段代码,我发现当他们这样做时,查询不会对表使用正确的索引,而只会进行自然读取。

是否有实现此目标的最佳实践方法?也许是一种告诉参数返回所有值的方法,或者必须修改脚本以在需要所有值时完全删除 where 子句?

编辑:顺便说一句,这是 Delphi 7(与 Firebird 1.5 相悖,很抱歉漏掉了)

4

5 回答 5

2

当您使用已弃用的 BDE 时,这可能是从 BDE 迁移到 3d 方解决方案的另一个原因。AnyDAC(UniDAC,可能还有其他人。大多数是商业库)具有宏,允许根据宏值动态更改 SQL 命令文本。因此,您的查询可能会写成:

ADQuery1.SQL.Text := 'select * from clients {IF &clientid} where clientid = &clientid {FI}';

if clientid >= 0 then
  // to get a single record
  ADQuery1.Macros[0].AsInteger := clientid
else
  // to get all records
  ADQuery1.Macros[0].Clear;

ADQuery1.Open;
于 2012-09-14T05:30:20.993 回答
0

最好使用两个查询:

if (clientid <> -1) then
begin
  DBComp.SQL.Text := 'select * from clients where (clientid = :clientid)';
  DBComp.ParamByName('clientid').Value := clientid;
end else
begin
  DBComp.SQL.Text := 'select * from clients';
end;
DBComp.Open;
...

或者:

DBComp.SQL.BeginUpdate;
try
  DBComp.SQL.Clear;
  DBComp.SQL.Add('select * from clients');
  if (clientid <> -1) then
    DBComp.SQL.Add('where (clientid = :clientid)');
finally
  DBComp.SQL.EndUpdate;
end;

if (clientid <> -1) then
  DBComp.ParamByName('clientid').Value := clientid;

DBComp.Open;
...
于 2012-09-14T00:50:21.777 回答
0

我会用这个:

SELECT * FROM CLIENTS WHERE clientid = :clientid or :clientid IS NULL
于 2012-09-14T13:06:05.023 回答
0

对于带有“可选”参数的查询,我总是使用 ISNULL(MSSQL 或 NVL Oracle),即。

SELECT * FROM clients WHERE ISNULL(:clientid, clientid) = clientid

将参数设置为NULL然后选择所有记录。您还必须注意表字段中的 NULL 值,因为NULL <> NULL. 您可以通过稍作修改来克服这一点:

SELECT * FROM clients WHERE COALESCE(:clientid, clientid, -1) = ISNULL(clientid, -1)
于 2012-09-14T06:27:01.830 回答
0

Remy 的答案可能会重新表述为单个查询。如果您准备一次然后重新打开多次,这可能会更好。

select * from clients where (clientid = :clientid)
                        and (:clientid is not null)
  UNION ALL
select * from clients where (:clientid is null)

这只是将两个不同的查询(具有相同的结果向量)聚合在一起。条件只是关闭其中一个。使用会是这样的:

 DBComp.Prepare.
   ...
 DBComp.Close;
 DBComp.ParamByName('clientid').Value := clientid;
 DBComp.Open;
   ...
 DBComp.Close;
 DBComp.ParamByName('clientid').Clear;
 DBComp.Open;

但是,此查询将依赖 SQL Server优化器功能来提取查询不变量(:clientid 为 [not] null)并完全启用/禁用查询。但是,您的原始查询也取决于此。


为什么仍然使用过时的 FB 1.5 ?FB 2.5.2 在那里工作不会更好吗?我认为您的原始查询表述不佳。

  select * from clients where (:clientid = -1) or  ((clientid = :clientid) and (:clientid <> -1))

在 SQL Server 优化器上可能会更容易。但我认为 FB 可以在那里做得更好。稍后尝试下载 FB,并使用 IBExpert 或 FlameRobin 等 IDE 在其中运行您的查询。重新排列括号并将 -1 更改为 NULL 是显而易见的尝试。


现在使用 BDE 很脆弱。它不是很快,限制了数据类型和连接性(例如没有 FB/IB 事件)。并且会出现与 Vista/Win7 和 Win64 的各种兼容性问题。如果 FB/IB 是您选择的服务器,请考虑切换到一些现代组件集:


显示表格和索引的定义以及这些索引的选择性也是一件好事。

于 2012-09-17T06:15:44.047 回答