Почему временная таблица не разрешена в хранимой процедуре в 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.


С 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), и это очень быстро по сравнению с кучей сложных соединений.

Я никогда не тратил время, чтобы узнать, как использовать предложение "план" (или заставить его работать правильно), поэтому в основном я использую этот метод для создания плана через код, когда я получаю медленные запросы, если это имеет смысл.