Firebird и хранимые процедуры: если существует, то иначе

Я пытаюсь создать хранимую процедуру для firebird 2.1 (это версия, которую нужно использовать), но я немного застрял, поэтому любая помощь приветствуется. Окончательная версия должна сравнить 4 значения с таблицей и получить либо первичный идентификатор, если значение существует, либо создать новую запись в таблице и вернуть новый первичный идентификатор.

Но я застрял только с одним поиском значения, и он еще даже не использует переменную.

SET TERM ^ ;

CREATE PROCEDURE TESTSP 
 ( A Varchar(64) ) 
RETURNS 
 ( RESULT Integer )
AS 

BEGIN
IF (EXISTS (SELECT PRIMARYID FROM TABLENAME WHERE FIELD = 'Some string')) then
    SELECT PRIMARYID FROM TABLENAME WHERE FIELD = 'Some string' into :primaryid;
    result = PRIMARYID;
ELSE 
    INSERT INTO TABLENAME (FIELD) VALUES ('Some string');
    result = gen_id(GEN_TABLEID, 0);
END^

SET TERM ; ^

Я получаю «Токен неизвестен» для команды Else.

Обновление после ответов: теперь я хочу использовать 4 переменные и вернуть 4 результата. Я думаю, что для этого мне нужен цикл for, но в firebird функция for означает что-то другое. Итак, каким будет путь?

SET TERM ^ ;

CREATE PROCEDURE TESTSP 
 ( value1 Varchar(64) ) 
RETURNS 
 ( RESULT1 Integer )
AS 

BEGIN
    IF (EXISTS (SELECT PRIMARYID FROM TABLENAME WHERE FIELD = :value1)) then
        SELECT PRIMARYID FROM TABLENAME WHERE FIELD = value1 into :result1;
    ELSE BEGIN
        result1 = gen_id(GEN_TABLEID, 1);
        INSERT INTO TABLENAME (PRIMARYID, FIELD) VALUES (:result1, :value1);
    END
    suspend;
END^

SET TERM ; ^

person Giancarlo    schedule 30.12.2013    source источник


Ответы (3)


Как уже ответил Тико, вы должны использовать begin / end для группировки нескольких операторов в части then / else. Ошибка, связанная с неизвестным столбцом PRIMARYID, связана с тем, что вы ссылаетесь на него, не объявив для него локальную переменную. Попробуй это:

CREATE PROCEDURE TESTSP ( A Varchar(64) ) 
RETURNS ( RESULT Integer )
AS 
BEGIN
  -- initialize the result
  Result = NULL;
  -- check is the string already in table
  SELECT PRIMARYID FROM TABLENAME WHERE FIELD = 'Some string' into :Result;
  IF (Result is NULL) then
    INSERT INTO TABLENAME(PRIMARYID, FIELD) VALUES(gen_id(GEN_TABLEID, 1), 'Some string') RETURNING PRIMARYID INTO :Result;
END^
person ain    schedule 31.12.2013
comment
Привет, это работает, но при попытке использовать переменную A (или значение1) (значение1 Varchar(64)) в том месте, где Поле = значение1 в :Результат; Я снова получаю неизвестный столбец. Если я удвою кавычки value1, это будет означать буквальное. Итак, как я могу использовать переменную? - person Giancarlo; 31.12.2013
comment
Префикс его с двоеточием, вот как вы отделяете параметры/переменные от столбцов в операторах SQL в PSQL, т.е. :A или :value1 - person ain; 31.12.2013
comment
Привет, это работа над созданием SP. Но при выполнении его с помощью flamerobin, например: SELECT p.RESULT FROM TESTSP(VALUE1) p дает неизвестный столбец VALUE1. И я хотел бы выполнить эту функцию 4 раза для 4 значений и получить 4 результата. У вас есть совет, как с этим справиться? Я обновил свой оригинальный пост со всеми ответами, чтобы составить полный пример для других с тем же вопросом. - person Giancarlo; 31.12.2013
comment
Flamerobin не знает, как заменить value1 каким-либо значением, вы должны использовать какое-то константное значение вместо имени переменной, т.е. SELECT p.RESULT FROM TESTSP('foo') p . Что касается цикла, это довольно сложно, когда входные данные поступают из разных параметров для каждого шага, поэтому вам лучше развернуть цикл - написать один и тот же набор операторов для каждого шага цикла, используя разные параметры. - person ain; 31.12.2013

Я думаю, что ваша хранимая процедура должна выглядеть так:

SET TERM ^ ; 
CREATE PROCEDURE TESTSP 
  ( A Varchar(64) ) 
  RETURNS ( result Integer ) 
AS 
BEGIN 
  IF (EXISTS (SELECT PRIMARYID 
              FROM TABLENAME 
              WHERE FIELD = 'Some string')) then 
     SELECT PRIMARYID 
       FROM TABLENAME 
       WHERE FIELD = 'Some string' 
       into :result;
  ELSE BEGIN
     result = gen_id(GEN_TABLEID, 1); 
     INSERT INTO TABLENAME 
       (PRIMARYID, FIELD) 
       VALUES (:result,  'Some string'); 
  END
END^ 
SET TERM ; ^
person guetlaur    schedule 31.12.2013

Если у вас есть несколько инструкций для предложения then и/или else, вы должны использовать BEGIN ... END-блок!

SET TERM ^ ;

CREATE PROCEDURE TESTSP 
 ( A Varchar(64) ) 
RETURNS 
 ( RESULT Integer )
AS 

BEGIN
IF (EXISTS (SELECT PRIMARYID FROM TABLENAME WHERE FIELD = 'Some string')) then
  BEGIN
    SELECT PRIMARYID FROM TABLENAME WHERE FIELD = 'Some string' into :primaryid;
    result = PRIMARYID;
  END
ELSE 
  BEGIN
    INSERT INTO TABLENAME (FIELD) VALUES ('Some string');
    result = gen_id(GEN_TABLEID, 0);
  END
END^

SET TERM ; ^
person tico    schedule 30.12.2013
comment
Привет, Тико. Спасибо за ответ, я пробовал это раньше, но это тоже не сработало. Затем я получаю сообщение об ошибке, что столбец PRIMARYID неизвестен - person Giancarlo; 31.12.2013