与宏的Firedac多参数查询

时间:2016-12-22 09:52:24

标签: sql delphi macros firebird firedac

我创建了一个返回整数值的主查询,有2个次要条件来限制在侧面组合框中选择。

img1

一切都适用于设定的参数。我希望我能用侧面组合框关闭或打开这些条件,我该怎么办?

我的代码在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)

1 个答案:

答案 0 :(得分:1)

1)可选地忽略条件的典型方法是再添加一个&#34;切换&#34;参数。考虑一下这个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对象提供合理的名字!
那个FDQuery3Checkbox3 Combobox5 - 将它们全部重命名,给了他们一些有意义的名字!{/ p>

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文本。 如果参数将被忽略 - 那么只需删除它!

这个选项不是普遍的,但它有好的和坏的方面。 但是在你的情况下,它宁愿做好事也不做任何事 - 因为你有人重新打开查询,而人类不能每秒做一次而不是每秒一次。

好:然后服务器获取您准备QUERY PLAN的SQL文本。如何获取数据的内部程序。并且它还不知道您的参数是什么,因此它准备PLAN以始终检查这些参数。即使你以后会忽略它们。有时它可能会使服务器选择缓慢的PLAN,如果它知道参数不会被使用,它可以选择更快的。有时它没有任何区别。运气的游戏。

错误:如果您保持SQL文本相同,那么您可以PREPARE一次查询,当您使用不同参数重新打开查询时,服务器不会构建不同的PLAN。但是,如果您确实更改了SQL文本,那么服务器必须解析该新查询并在它为您提供数据之前再次准备PLAN。有时,当您打开关闭查询(例如每秒1000次)时需要相当长的时间。当然,当你使用人工设置那些复选框,组合框然后按下按钮时,他不会经常这样做,所以在这种情况下风险是没有实际意义的。

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

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 
....