在Firebird SQL中使用循环

时间:2019-02-07 03:28:31

标签: firebird

我希望我的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

使用以上代码的结果是:

Qty Total Qty
1       4

但是,我想要的是:

使用以上代码的结果是:

Qty Total Qty
1       4
2       4
3       4
4       4

我了解While循环将类似于:

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

1 个答案:

答案 0 :(得分:1)

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

另请参见Wikipedia中的“限制结果行”专栏文章:https://en.wikipedia.org/wiki/Select_%28SQL%29#Limiting_result_rows

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

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

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

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


由于Mark的猜测似乎比我更好,所以为将来的猜测提供了一些轮廓。

SP是SQL存储过程的标准缩写。 Firebird的Execute 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(存储过程)连接
  • 避免使用空参数值执行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 from execute block?

因此,您必须准确地为您的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查询,它仍会返回“行集”。他们通常会这么做,但是谁知道呢。