为什么在 Firebird 的存储过程中不允许临时 table?
Why temporary table is not allowed in stored procedure in Firebird?
我正在尝试在 Firebird 数据库的存储过程中创建临时 table。
我的存储过程列表:
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
CREATE GLOBAL TEMPORARY TABLE
is a regular DDL statement that is processed by the engine the same way as a CREATE TABLE statement is processed. Accordingly, it not
possible to create or drop a GTT within a stored procedure or trigger.
您可以使用 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^
Firebird 不允许您在存储过程中使用 DDL,因此 CREATE
语句在 PSQL 中是不允许的。如 you can work around this limitation by using EXECUTE STATEMENT
.
所示
但是,global temporary table 背后的想法是您创建一次,它们将继续存在,以便以后使用。数据只对创建数据的连接可见,数据在事务提交(ON COMMIT DELETE ROWS
)或连接关闭(ON COMMIT PRESERVE ROWS
)后删除,具体取决于全局临时table的类型.
来自 Firebird 3.0 语言参考:
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.
因此,与其尝试在存储过程中创建全局临时 table,不如先创建它,然后再创建 使用 已定义的 GTT 的存储过程。
为了详细说明上述其他正确答案,我主要使用临时表来解决性能问题,例如当我有一个参数化的数据子集需要针对更大的集合进行查询时,例如:
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' 子句(或让它正常工作),所以基本上我使用这种技术通过代码生成计划,当我遇到缓慢的查询时,如果有道理。
我正在尝试在 Firebird 数据库的存储过程中创建临时 table。
我的存储过程列表:
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
CREATE GLOBAL TEMPORARY TABLE
is a regular DDL statement that is processed by the engine the same way as a CREATE TABLE statement is processed. Accordingly, it not possible to create or drop a GTT within a stored procedure or trigger.
您可以使用 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^
Firebird 不允许您在存储过程中使用 DDL,因此 CREATE
语句在 PSQL 中是不允许的。如 EXECUTE STATEMENT
.
但是,global temporary table 背后的想法是您创建一次,它们将继续存在,以便以后使用。数据只对创建数据的连接可见,数据在事务提交(ON COMMIT DELETE ROWS
)或连接关闭(ON COMMIT PRESERVE ROWS
)后删除,具体取决于全局临时table的类型.
来自 Firebird 3.0 语言参考:
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.
因此,与其尝试在存储过程中创建全局临时 table,不如先创建它,然后再创建 使用 已定义的 GTT 的存储过程。
为了详细说明上述其他正确答案,我主要使用临时表来解决性能问题,例如当我有一个参数化的数据子集需要针对更大的集合进行查询时,例如:
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' 子句(或让它正常工作),所以基本上我使用这种技术通过代码生成计划,当我遇到缓慢的查询时,如果有道理。