Почему временная таблица не разрешена в хранимой процедуре в Firebird?
Я пытаюсь создать временную таблицу в хранимой процедуре в базе данных 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
заранее спасибо Роберт!--3-->
3 ответов
Firebird не позволяет использовать DDL внутри хранимых процедур, поэтому CREATE
операторы запрещены в PSQL. Как указано в ответ lad2025 вы можете обойти это ограничение с помощью EXECUTE STATEMENT
.
однако, идея за глобальные временная таблица это то, что вы создаете его один раз, и они продолжают существовать, чтобы их можно было использовать позже. Данные видны только для соединения, создавшего данные, и данные удаляются после фиксации транзакции (ON COMMIT DELETE ROWS
) или связи закрыть (ON COMMIT PRESERVE ROWS
) в зависимости от типа глобальной временной таблицы.
из обновления ссылки на язык:
глобальные временные таблицы имеют постоянные метаданные, но их содержимое связано с транзакциями (по умолчанию) или подключением. Каждая транзакция или соединение имеет свой собственный экземпляр GTT, изолированный от всех остальных. Экземпляры создаются только в том случае, если ГЦГ ссылается и уничтожается при завершении транзакции или отключении.
поэтому вместо того, чтобы пытаться создать глобальную временную таблицу внутри хранимой процедуры, сначала создайте ее, а затем создайте хранимую процедуру, которая использует уже определенный GTT.
СОЗДАТЬ ГЛОБАЛЬНУЮ ВРЕМЕННУЮ ТАБЛИЦУ
- это обычный оператор DDL, который обрабатывается обработчиком так же, как обрабатывается оператор CREATE TABLE. соответственно, он не можно создать или удалить GTT в хранимой процедуре или триггере.
можно использовать Dynamic-SQL и обернуть ваш код EXECUTE STATEMENT
as решение:
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^
чтобы уточнить другие приведенные выше правильные ответы, я использую временные таблицы в основном для проблем производительности, например, когда у меня есть параметризованное подмножество данных, которое должно быть запросом против большего набора, такого как:
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'ERS, но это имеет для меня наибольший смысл (переносить технику из моих дней dBase/VFP), и это очень быстро по сравнению с кучей сложных соединений.
Я никогда не тратил время, чтобы узнать, как использовать предложение "план" (или заставить его работать правильно), поэтому в основном я использую этот метод для создания плана через код, когда я получаю медленные запросы, если это имеет смысл.