首页 > 解决方案 > 在 Firebird SQL 中使用循环

问题描述

我希望我的 Firebird SQL 在满足条件时循环遍历部分代码。

一开始我什至不认为这是可能的。但是我已经阅读了一些内容,现在相信我可以使用 WHILE 循环。

我知道 FOR 循环不是我想要的,因为它适用于整个代码,而不仅仅是它的一部分。

我在 Excel 中使用它,并且可以使用一些 VBA 代码来做我想做的事,但如果我可以通过 Firebird SQL 完成这一切会更好,因为我可以在其他地方应用它。

SELECT 
'1' as "Qty",
'of ' || ALP3.PROPERTYVALUE AS "Total Qty"

FROM ASSEMBLYLINES
LEFT JOIN ASSEMBLYLINEPROPS ALP1 ON  ALP1.HEADERSYSUNIQUEID = ASSEMBLYLINES.SYSUNIQUEID AND ALP1.PROPERTYNAME = 'Process2'
LEFT JOIN ASSEMBLYLINEPROPS ALP2 ON  ALP2.HEADERSYSUNIQUEID = ASSEMBLYLINES.SYSUNIQUEID AND ALP2.PROPERTYNAME = 'Process3'
LEFT JOIN ASSEMBLYLINEPROPS ALP3 ON  ALP3.HEADERSYSUNIQUEID = ASSEMBLYLINES.SYSUNIQUEID AND ALP3.PROPERTYNAME = 'Job Quantity'
LEFT JOIN ASSEMBLYLINEPROPS ALP4 ON  ALP4.HEADERSYSUNIQUEID = ASSEMBLYLINES.SYSUNIQUEID AND ALP4.PROPERTYNAME = 'Drawing No'

WHERE ASSEMBLYLINES.ORDERNUMBER='16708R01' 
AND ASSEMBLYLINES.LINECODE='FABPART'
AND ASSEMBLYLINES.SYSUSERCREATED <> 'EXTERNAL USER'

ORDER BY ALP4.PROPERTYVALUE

我使用上面代码的结果是:

数量 总数量
1 4

但是,我想要的是:

我使用上面代码的结果是:

数量 总数量
1 4
2 4
3 4
4 4

我了解 While 循环将类似于:

While Qty <= ALP3.PROPERTYVALUE Do
    <<output>>
Loop

标签: firebird

解决方案


Qty Total Qty
1       4
2       4
3       4
4       4


I understand the While loop would be something like:
While Qty <= ALP3.PROPERTYVALUE Do
    <<output>>
Loop

因此,您的“数量”列实际上不是一些真实数据的数量(如货船中的集装箱数量),而是一些输出报告/网格中的行号。然后你想要的是将输出“行集” - 矩阵、表格、网格 - 限制为前 N 行。

好吧,这正是它的完成方式,只要求第一行。

Select FIRST(4) column1, column2, column3 
From table 1
Where condition1 and condition2 or condition3

请参阅文档中的“第一个”子句:https ://www.firebirdsql.org/file/documentation/reference_manuals/fblangref25-en/html/fblangref25-dml-select.html

另请参阅维基百科中的“限制结果行”章节:https ://en.wikipedia.org/wiki/Select_%28SQL%29#Limiting_result_rows

您也可以从 Firebird 版本 3 开始使用“窗口函数”,但对于“只给我前 N 行”这样的简单任务来说,它们有点过分了。

现在,还有另一种方法可以嵌入完全自愿的条件,但这来自“丑陋的黑客”工具集,并且在运行来自不同客户端程序的多个同时连接的典型情况下不起作用。您可以使用“生成器”作为 WHILE 子句的一部分:

Select .....
Where (GEN_ID(cancel_generator_name, 0) = 0) AND ( ...you normal conditions...)

您在查询之前将生成器值设置为 0,并且您的客户端在读取数据时评估您选择的一些条件,并且当它想要时 - 从另一个 SQL 命令库对象发出生成器更改命令,该命令将立即跳过其余的查询。然而,虽然有时这是一种有用的技术,但仅限于非常特殊的罕见情况。


既然马克似乎比我更善于猜测,那么就为未来的猜测做一些概述。

SP 是 SQL 存储过程的标准缩写。FirebirdExecute Block本质上是一个匿名的非持久性 SP。

因此,我们从一个持久且命名的 SP 开始。

create or alter procedure SEQ (
    FROM_1_TO integer not null)
returns (
    COUNTER integer)
as
begin
  counter = 1;
  while ( counter <= from_1_to ) do begin
    suspend;
    counter = counter + 1;
  end
end

Select 1, s.counter from rdb$database, seq(5) s

CONSTANT    COUNTER
1   1
1   2
1   3
1   4
1   5

下一个问题是如何

  • 根据特定表行值将表与 SP(存储过程)联接
  • 避免使用 NULL 参数值执行 SP

答案是 - LEFT JOIN,如常见问题解答中所示:http ://www.firebirdfaq.org/faq143/

CREATE TABLE T2 (
    ID     INTEGER NOT NULL PRIMARY KEY,
    TITLE  VARCHAR(10) NOT NULL,
    QTY    INTEGER NOT NULL
);

INSERT INTO T2 (ID, TITLE, QTY) VALUES (1, 'aaaa', 2);
INSERT INTO T2 (ID, TITLE, QTY) VALUES (2, 'bbbb', 5);
INSERT INTO T2 (ID, TITLE, QTY) VALUES (3, 'ccccc', 4);

Select * from t2 t
left join seq(t.qty) s on 1=1

ID  TITLE   QTY COUNTER
1   aaaa    2   1
1   aaaa    2   2
2   bbbb    5   1
2   bbbb    5   2
2   bbbb    5   3
2   bbbb    5   4
2   bbbb    5   5
3   ccccc   4   1
3   ccccc   4   2
3   ccccc   4   3
3   ccccc   4   4

如果您对需要添加此行克隆的不同表/字段有许多不同的查询,那么拥有一个专用的反生成 SP 是有意义的。

但是,如果您只需要克隆一次这种相当奇特的行,那么使用您再也不需要的 SP 污染全局命名空间可能不是一个好主意。

不过,似乎无法从 EB 中进行选择:从执行块中选择?

select因此,您必须为您的声明制作一个特定的临时 EB 。可以说,这可能是匿名非持久性 EB 存在的原因。

execute block
   returns (ID INTEGER, TITLE VARCHAR(10), QTY INTEGER, COUNTER INTEGER)
as
begin
  for select
    id, title, qty from t2
    into :id, :title, :qty
  do begin
    counter = 1;
    while
      (counter <= qty)
    do begin
      suspend;
      counter = counter + 1;
    end
  end
end

但是,您的应用程序用来连接到 Firebird 的数据访问库应该明白,虽然这个查询不是 SELECT 查询,但它仍然返回“行集”。通常他们会这样做,但谁知道呢。


推荐阅读