【问题标题】:Firebird stored procedure with indexed variable using execute statement使用执行语句的带有索引变量的 Firebird 存储过程
【发布时间】:2021-07-15 13:42:28
【问题描述】:

如何在 Firebird 存储过程中使用索引变量?我的意思是,我有输出参数 ODATE1、ODATE2、ODATE3,我可以用作 ':ODATE' || COUNTER 循环设置值?

我有 2 个这样的表:

    1. T_EMPLOYEE
    ---------------
    | ID_E | NAME |
    ---------------
    | 1    | Anne |
    ---------------
    | 2    | Bob  |
    ---------------


    2. T_WORK
    ----------------------------
    | ID_W | DATE_W     | ID_E |
    ----------------------------
    | 1    | 2021-01-01 | 1    |
    ----------------------------
    | 2    | 2021-01-01 | 2    |
    ----------------------------
    | 3    | 2021-01-02 | 1    |
    ----------------------------
    | 4    | 2021-01-03 | 2    |
    ----------------------------

我想从那个表中创建一个存储过程来得到这个结果:

    DASHBOARD
    -----------------------------------------------------------
    | OID_E | ONAME     | ODATE1     | ODATE2     | ODATE3     |
    ----------------------------------------------------------
    | 1     | Anne      |     1      |      1     |      0     |
    -----------------------------------------------------------
    | 2     | Bob       |     1      |      0     |      1     |
    -----------------------------------------------------------

我尝试在存储过程中像这样使用EXECUTE STATEMENT

    DECLARE VARIABLE COUNTER INT;
    BEGIN

    FOR 
        SELECT ID_E, NAME FROM T_EMPLOYEE 
        INTO :OID_E, :ONAME
    D0
    BEGIN
        COUNTER = 1;
        WHILE (COUNTER<=3) DO
        BEGIN 
           EXECUTE STATEMENT 'SELECT COUNT(*) FROM T_WORK WHERE DATE_W = ''2021-01-0' || COUNTER ||
           ''' AND ID_E = ' || :OID_E || ' INTO :ODATE' || COUNTER;
    
           COUNTER = COUNTER + 1;
        END 
        SUSPEND;
    END 
    
    END  /*procedure*/

程序无法编译。 然后我尝试了这样简单的没有 COUNTER 索引替换:

    DECLARE VARIABLE COUNTER INT;
    BEGIN

    FOR 
        SELECT ID_E, NAME FROM T_EMPLOYEE 
        INTO :OID_E, :ONAME
    D0
    BEGIN
        COUNTER = 1;
        WHILE (COUNTER<=3) DO
        BEGIN 
           EXECUTE STATEMENT 'SELECT COUNT(*) FROM T_WORK WHERE ID_E = :OID_E ' ||
           ' AND DATE_W =''2021-01-02'' INTO :ODATE2';

           COUNTER = COUNTER + 1;
        END 
        SUSPEND;
    END 
    
    END  /*procedure*/

程序可以编译,但是执行时会报这个错误:

    SQL Error:  Dynamic SQL Error SQL error code = @1 Token unknown - line @1, column @2 @1. Error Code: -104. Invalid token

请给我一些见解。如何使用 EXECUTE STATEMENT 进行灵活循环来设置索引变量。 或者您有其他解决方案来满足我的需求。

附加信息:Firebird v2.5

【问题讨论】:

  • 您到底想达到什么目的?以及您是如何执行此操作的,因为显然您使用的任何东西都没有正确呈现 Firebird 错误消息。无论如何,问题之一是您在传递给EXECUTE STATEMENT 的语句文本中有一个INTO 子句。传递给EXECUTE STATEMENT 的语句应该是DSQL,而INTO 只在PSQL 中有效。您需要使用INTO 作为EXECUTE STATEMENT 本身的子句。
  • 在任何情况下,查看表和所需的输出,您甚至不需要EXECUTE STATEMENT,您可以使用单个查询来完成此操作(即使不使用存储过程)。
  • 转置(数据透视表,象在苏联调用的象棋表)在客户端应用程序(报告生成器等)中比 RDBMS 更好。这只是应用程序适合的任务,而不是数据库引擎
  • 嗨@MarkRotteveel,实际上我想制作一个每月31天的表格,显示我员工的工作时间。我在这里展示的示例使用t_work中的单个日期列,但是在这里,我有两列包含开始日期和结束日期。感谢您在下面的简单回答,我将尝试适应检查日期是否在 t_work 中的日期之间。非常感谢..我会尽快通知结果..
  • 这正是您在数据库服务器中不应该做的事情。它在工作中使用了错误的工具,例如用叉子喝茶。这个问题实际上似乎与 stackoverflow.com/questions/48262968/…stackoverflow.com/questions/55449169/… 以及许多其他问题重复

标签: stored-procedures firebird firebird2.5 firebird-psql


【解决方案1】:

您不能像这样动态引用 PSQL 变量(包括参数)。但是,您无需跳过所有这些障碍即可获得所需的结果。

你可以使用类似下面的东西(甚至不需要过程):

select e.ID_E as OID_E, e.NAME as ONAME, 
  count(case when w.DATE_W = date '2021-01-01' then 1 end) as ODATE1,
  count(case when w.DATE_W = date '2021-01-02' then 1 end) as ODATE2,
  count(case when w.DATE_W = date '2021-01-03' then 1 end) as ODATE3
from T_EMPLOYEE e
inner join T_WORK w
  on w.ID_E = e.ID_E
group by e.ID_E, e.NAME
order by e.ID_E

小提琴:https://dbfiddle.uk/?rdbms=firebird_3.0&fiddle=59066afc0fd7f6b5cb87eac99164e899

【讨论】:

  • 非常感谢。我看过你发布的小提琴..它用一个简单的代码完成..但我需要稍微调整一下..因为实际上在 t_work 我有两个日期列,开始日期和结束日期..我想显示 31 天表员工是否每天工作.. 我会尽快通知你
  • @UmarGumai 我回答了你原来的问题。如果您需要其他内容,那么我建议您发布一个新问题。 Stack Overflow 上的问题不应该是一个移动的目标。
  • 非常感谢,是的,我已经得到了您对我最初问题的回答。它运作良好。您的简单解决方案可以保护我的生命。
猜你喜欢
  • 1970-01-01
  • 2019-05-11
  • 1970-01-01
  • 2015-07-28
  • 1970-01-01
  • 1970-01-01
  • 2013-07-16
  • 2015-01-17
  • 1970-01-01
相关资源
最近更新 更多