8

我正在尝试在 Firebird 数据库的存储过程中创建临时表。

我的存储过程清单:

SET TERM ^ ;

CREATE PROCEDURE initNATIONALHEALTHFUNDS
 
AS BEGIN

  CREATE GLOBAL TEMPORARY TABLE temp_FUNDS 
  (
    NATIONALHEALTHFUNDID Integer NOT NULL,
    NAME Varchar(128) NOT NULL,
    CODE Integer NOT NULL
  )
  ON COMMIT PRESERVE ROWS;
  commit;
  
 INSERT INTO tempFUNDS (NATIONALHEALTHFUNDID, CODE, NAME)  VALUES ( 01 ,01 , 'Some Foundation');

    
  MERGE INTO NATIONALHEALTHFUNDS  AS target 
   USING tempFUNDS AS source 
   ON target.NATIONALHEALTHFUNDID = source.NATIONALHEALTHFUNDID
   WHEN NOT MATCHED THEN 
    INSERT (NATIONALHEALTHFUNDID, CODE, NAME) VALUES (source.NATIONALHEALTHFUNDID, source.CODE, source.NAME);
    
  drop  TABLE tempFUNDS;
END^

SET TERM ; ^

每次我尝试创建此过程时,都会出现错误:

    Engine Code    : 335544569
Engine Message :
Dynamic SQL Error
SQL error code = -104
Token unknown - line 7, column 3
CREATE


Total execution time: 0.015s

我做错了什么?我正在使用 Firebird 3.0 RC

4

3 回答 3

5

Firebird doesn't allow you to use DDL inside stored procedures, so CREATE statements are disallowed in PSQL. As indicated in the answer by lad2025 you can work around this limitation by using EXECUTE STATEMENT.

However, the idea behind a global temporary table is that you create it once, and they continue to exist so they can be used later. The data is only visible to the connection that created the data, and the data is deleted after transaction commit (ON COMMIT DELETE ROWS) or connection close (ON COMMIT PRESERVE ROWS) depending on the type of global temporary table.

From the Firebird 3.0 Language Reference:

Global temporary tables have persistent metadata, but their contents are transaction-bound (the default) or connection-bound. Every transaction or connection has its own private instance of a GTT, isolated from all the others. Instances are only created if and when the GTT is referenced. They are destroyed when the transaction ends or on disconnection.

So instead of trying to create the global temporary table inside your stored procedure, create it first, then create your stored procedure that uses the already defined GTT.

于 2015-11-28T17:18:04.507 回答
4

来自GTT 文档

创建全局临时表

是由引擎处理的常规 DDL 语句,其处理方式与处理 CREATE TABLE 语句的方式相同。因此,不可能在存储过程或触发器中创建或删除 GTT。

您可以使用Dynamic-SQL并将代码包装EXECUTE STATEMENT为解决方法:

SET TERM ^ ;

CREATE PROCEDURE initNATIONALHEALTHFUNDS
AS BEGIN

EXECUTE STATEMENT
  'CREATE GLOBAL TEMPORARY TABLE temp_FUNDS 
  (
    NATIONALHEALTHFUNDID Integer NOT NULL,
    NAME Varchar(128) NOT NULL,
    CODE Integer NOT NULL
  )
  ON COMMIT PRESERVE ROWS;
  commit;';

 ...

END^
于 2015-11-28T15:09:32.270 回答
0

只是为了详细说明上述其他正确答案,我主要使用临时表来解决性能问题,例如当我有一个参数化的数据子集需要针对更大的集合进行查询时,例如:

select * from MAIN_TABLE
   where MAIN_TABLE.ID in (select ID from GTT$IDS)

其中 GTT$IDS 填充了 ID 的子集。

有时,对于高度复杂的过程,我必须使用多个临时表,因此我在元数据中创建它们(当然是在 PSQL 语句之外),如下所示:

create global temporary table GTT$IDS_1 (INT1 integer, INT2 integer);
create index IDX_GTT$IDS_11 on GTT$IDS_1 (INT1);
create index IDX_GTT$IDS_12 on GTT$IDS_1 (INT2);

create global temporary table GTT$IDS_2
...

create global temporary table GTT$IDS_3
...

对于一些高级 SQL 人员来说,这样做可能过于简单,但对我来说最有意义(继承了我 dBase/VFP 时代的技术),并且与一堆复杂的连接相比,它的速度非常快。

我从来没有真正花时间学习如何使用“PLAN”子句(或让它正常工作),所以基本上当我遇到慢查询时,我会使用这种技术通过代码生成 PLAN,如果这有意义的话。

于 2015-12-20T16:00:08.393 回答