【问题标题】:Firedac multiparametric query with macroFiredac 多参数查询与宏
【发布时间】:2016-12-22 09:52:23
【问题描述】:

我创建了返回整体值的主查询,并带有 2 个辅助条件来限制在侧面组合框中进行的选择。

一切都与设置的参数一起工作。我希望我可以用侧面组合框关闭或打开这些条件,我应该如何进行?

我的代码在 Delphi 中:

procedure TForm1.Button3Click(Sender: TObject);
      begin
                  FDQuery3.Close;
                  FDquery3.Params[0].Value := Datetimepicker1.Date;
                  FDquery3.Params[1].Value := Datetimepicker2.Date;
                  FDQuery3.Params[2].Value := Combobox3.Items [Combobox3.Itemindex];
                  FDQuery3.Params[3].Value := Combobox5.Items [Combobox5.Itemindex];
                  FDQuery3.Open;

      end;

SQL 文本为:

select
  G.NUM_PROG,T.DATA,T.ORA,C.DESCRIZIONE, 
  (select DESKEY from ANAFORN where CODKEY=T.CODICE ) as Cliente,
  O.NOMINATIVO, T.TERMINALE,T.INCASSO 
from LG_RIGHE G 
  inner join LG_TESTA T on G.NUM_PROG =T.NUM_PROG 
  inner join OPERATORI O on T.OPERATORE = O.CODICE 
  inner join LG_CAUSA C on T.CAUSALE = C.CODICE 
where T.DATA >= :data1 
  and T.DATA <= :data2 
  and T.INCASSO = :pagamento 
  and T.TERMINALE = :terminale 
order by G.NUM_PROG  

我只想打开/关闭 Params[2][ 和 Params[3](名称:pagamento,terminale)

【问题讨论】:

  • 能否请您澄清您的问题,目前我不知道您在问什么,可能其他人也不知道。
  • 向我们展示查询本身。 FDQuery3.SQL.Text 值是什么?另外:最好不要使用 Param/Field 的 .Value 属性。改用强类型的.AsDateTime.AsString
  • 选择 G.NUM_PROG,T.DATA,T.ORA,C.DESCRIZIONE,(从 ANAFORN 中选择 DESKEY,其中 CODKEY=T.CODICE )作为 Cliente,O.NOMINATIVO,T.TERMINALE,T。 INCASSO 来自 LG_RIGHE G 内部连接 ​​LG_TESTA T 上 G.NUM_PROG =T.NUM_PROG 内部连接 ​​OPERATORI O 上 T.OPERATORE = O.CODICE 内部连接 ​​LG_CAUSA C 上 T.CAUSALE = C.CODICE 其中 T.DATA >= :data1 和 T .DATA
  • 我只想打开/关闭 Params[2][ 和 Params[3](名称:pagamento,terminale)
  • 您将编辑文本并添加重要的细节,而不是将它们深埋在 cmets 线程中。无法阅读评论,它必须易于获取和格式化

标签: sql delphi macros firebird firedac


【解决方案1】:

1) 可选择忽略条件的典型方法是再添加一个“切换”参数。考虑一下这个 Delphi 代码

Result := True; // or False. Actually - some previous part of formula
If Need_Check_Option_A then
   Result := Result and ( Option_A > 20 ); 
If Need_Check_Option_B then
   Result := Result and ( Option_B < 10 ); 

明白了吗? 但是很长就是,有没有更简洁的写法?

Result := .....some other parts.... 
   and (Ignore_Option_A or (Option_A > 20 ))
   and (Ignore_Option_B or (Option_A < 10 ))
   and ....

现在让我们将它从 Delphi 重新表述为 SQL WHERE 子句

WHERE (.......) and (......)
  AND ( ( :Use_pagamento = 0 ) or ( T.INCASSO = :pagamento ) )
  AND ( ( :Use_terminale = 0 ) or ( T.TERMINALE = :terminale ) )

无论您是否将 USE_xxxx 参数设置为零(类似于 false),那么第二次检查将是快捷方式,被忽略。

调用代码类似于

FDquery3.ParamByName('data1').AsDate := Datetimepicker1.Date;
FDquery3.ParamByName('data2').AsDate := Datetimepicker2.Date;
FDQuery3.ParamByName('pagamento').AsString := Combobox3.Items [Combobox3.Itemindex];
FDQuery3.ParamByName('terminale').AsString := Combobox5.Items [Combobox5.Itemindex];
FDQuery3.ParamByName('Use_pagamento').AsSmallInt := Ord( CheckBox3.Checked );
FDQuery3.ParamByName('Use_terminale').AsSmallInt := Ord( CheckBox5.Checked );

更多建议如下:

2) 使用像 ComboBox3 这样的名称是不好的。你不会明白它们的意思,它们的目的是什么。看看你的 SQL - 你在那里给名字!你不喜欢

SELECT FIELD1, FIELD2 FROM TABLE1 WHERE FIELD3 < :PARAM1

你也必须给你的 Delphi 对象起合理的名字!
FDQuery3Checkbox3Combobox5 - 全部重命名,给它们一些有意义的名字!

3) 你有一个嵌套选择作为Cliente 列。除非非常特殊的情况是缓慢且低效的 - 也将其更改为JOIN(如果有时没有匹配值,可能会更改为LEFT JOIN

select
  G.NUM_PROG,T.DATA,T.ORA,C.DESCRIZIONE, 
--  (select DESKEY from ANAFORN where CODKEY=T.CODICE ) as Cliente,
  A.DESKEY as Cliente,
  O.NOMINATIVO, T.TERMINALE,T.INCASSO 
from LG_RIGHE G 
  inner join LG_TESTA T on G.NUM_PROG =T.NUM_PROG 
  inner join OPERATORI O on T.OPERATORE = O.CODICE 
  inner join LG_CAUSA C on T.CAUSALE = C.CODICE 
  /* left */ join ANAFORN A on A.CODKEY=T.CODICE 
where T.DATA >= :data1 
  and T.DATA <= :data2 
  AND ( ( :Use_pagamento = 0 ) or ( T.INCASSO = :pagamento ) )
  AND ( ( :Use_terminale = 0 ) or ( T.TERMINALE = :terminale ) )
order by G.NUM_PROG  

4) 根据具体情况,您可能只想更改 SQL 文本。 如果该参数将被忽略 - 那么只需将其删除!

这个选项不是通用的,但它有好有坏。 但在您的情况下,它宁愿做善事也可能什么都不做 - 因为您需要人工重新打开查询,而人工执行此操作的频率不能超过每秒一次。

很好:然后服务器获取您的 SQL 文本并准备查询计划。如何获取数据的内部程序。而且它还不知道你的参数是什么,所以它准备 PLAN 总是检查这些参数。即使您以后会忽略它们。有时它可能会让服务器选择较慢的 PLAN,如果它知道不会使用该参数,它可以选择较快的 PLAN。有时它没有任何区别。运气游戏。

不好:如果你保持 SQL 文本相同,那么你可以PREPARE 查询一次,当你用不同的参数重新打开查询时,服务器不会构建不同的PLAN。但是,如果您确实更改了 SQL 文本,那么服务器将不得不解析该新查询并再次准备计划,然后才能为您提供数据。有时打开关闭查询会花费相当长的时间,例如每秒 1000 次。当然,当您使用人工设置这些复选框、组合框然后按下按钮时,他不会那么频繁地这样做,所以在这种情况下风险是没有实际意义的。

所以在你的情况下,你可能会做这样的事情而不是引入那些切换参数:

var qt: TStrings; // SQL query text
.....
qt := FDQuery3.SQL;

qt.Clear;  // changing SQL Text would auto-close the query
qt.Add('select G.NUM_PROG,T.DATA,T.ORA,C.DESCRIZIONE, ');
qt.Add('  A.DESKEY as Cliente, O.NOMINATIVO, T.TERMINALE,T.INCASSO ');
qt.Add('from LG_RIGHE G ');
qt.Add('  join LG_TESTA T on G.NUM_PROG = T.NUM_PROG ');
qt.Add('  left join ANAFORN A on A.CODKEY=T.CODICE');
qt.Add('  join OPERATORI O on T.OPERATORE = O.CODICE ');
qt.Add('  join LG_CAUSA C on T.CAUSALE = C.CODICE ');
qt.Add('where T.DATA >= :data1 and T.DATA <= :data2 ');

if CheckBox3.Checked then
   qt.Add('  and T.INCASSO = :pagamento ');
if CheckBox5.Checked then
   qt.Add('  and T.TERMINALE = :terminale ');

qt.Add('order by G.NUM_PROG'); 

FDquery3.ParamByName('data1').AsDate := Datetimepicker1.Date;
FDquery3.ParamByName('data2').AsDate := Datetimepicker2.Date;
if CheckBox3.Checked then
   FDQuery3.ParamByName('pagamento').AsString := Combobox3.Items [Combobox3.Itemindex];
if CheckBox3.Checked then
   FDQuery3.ParamByName('terminale').AsString := Combobox5.Items [Combobox5.Itemindex];

FDQuery3.Open;

在此选项中,您不会引入额外的切换参数,而是仅在用户检查使用它们时添加值参数。如果用户取消选中它们 - 那么您不会将它们包含在您的 SQL 文本中,因此您不会为它们分配任何值(无论如何它们都不会被发现)。

5) 您可以使用 BETWEEN - 它可能更容易阅读。

...
where ( T.DATA BETWEEN :data1 AND :data2 )
  and T.INCASSO = :pagamento 
....

【讨论】:

  • Combobox1.visible := checkbox1.checked
  • 工作完美,但现在我想在选中复选框时启用组合框的可见性。我不得不处理复选框的点击事件。procedure TForm1.CheckBox2Click(Sender: TObject);开始 if CheckBox2.Checked = true then combobox1.Enabled := true else combobox1.Enabled := false end;
  • 是的,您使用 OnClick 事件。但是你不需要那种可怕的 if-then-else。我上面的注释的单行会做同样的事情。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2013-07-01
  • 1970-01-01
  • 2023-02-25
  • 2011-01-04
  • 2022-10-21
  • 1970-01-01
相关资源
最近更新 更多