PostgreSQL" IF " синтаксическая ошибка

Я новичок в PostgreSQL, и у меня уже есть первая проблема..

Я написал код, чтобы понять, как работают транзакции, следуя пошаговому руководству.

чтобы сделать его коротким, Я создал 2 таблицы, пользователь и движения: в первом из них есть столбцы имя, электронная почта и кредит, во втором-Столбцы от, до, импорт.

Итак, я пытался так:

BEGIN;
INSERT INTO movements (from, to, import) VALUES ('mary', 'steve', 600);
UPDATE users SET credit = credit - 600 WHERE name = 'mary';
UPDATE users SET credit = credit + 600 WHERE name = 'steve';
--here comes the problem!
IF (SELECT credit FROM users WHERE name = 'mary') < 0 THEN
 ROLLBACK;
END IF
COMMIT;

Я всегда получаю ошибку:

ошибка: синтаксическая ошибка при или около "IF"

где я ошибаюсь?

P. S.: Не сосредоточиться на примере функциональности, это просто испытание для меня, чтобы понять сделок.. а теперь пункт IF...

5 ответов


Как уже говорит Йоханнес: вы смешиваете обычный SQL с PL / pgSQL, языком хранимых процедур. Ссылка, которую предоставляет Johannes, должна объяснить вам концепцию хранимых процедур.

Я так понимаю, вы делаете это как сценарий? Выполнение одного оператора за другим? Боюсь, вы можете делать только то, что хотите, внутри хранимой процедуры или функции, как вы ее называете. Это связано с тем, что при выполнении операторов таким образом каждый оператор стоит на своем собственный, не имеющий никакого отношения или информации относительно других заявлений.

кроме того, вы можете посмотреть на следующую ссылку для получения дополнительной информации о том, как использовать IF ... ЗАТЕМ... ЕЩЕ... END IF; conditionals внутри plpgsql:ссылке.


EDIT:

Я не знаю, разрешен ли откат в этот момент (потому что каждая хранимая процедура уже находится в своей собственной транзакции), но вы должны быть в состоянии понять это для себя, используя обширная документация @ http://www.postgresql.org. Вот пример функции с вашим кодом, также демонстрирующий другой синтаксис:

CREATE OR REPLACE FUNCTION public.test()
RETURNS integer AS
$$
DECLARE
tempvar integer;

BEGIN    
     tempvar := 1;

     INSERT INTO movements (from, to, import) VALUES ('mary', 'steve', 600);
     UPDATE users SET credit = credit - 600 WHERE name = 'mary';
     UPDATE users SET credit = credit + 600 WHERE name = 'steve';

     --here comes the problem!
     IF (SELECT credit FROM users WHERE name = 'mary') < 0 THEN
        ROLLBACK;
     END IF;

     RETURN tempvar;
END
$$
LANGUAGE 'plpgsql'
VOLATILE
CALLED ON NULL INPUT
SECURITY INVOKER;

однако, если вы действительно идете по этому пути, я рекомендую использовать менеджер БД GUI. Все это легче усвоить.


вы, кажется, используете plain SQL но IF оператор является частью PL/pgSQL процедурный язык, который является частью программы.


вы можете попробовать изменить часть IF, из:

IF (SELECT credit FROM users WHERE name = 'mary') < 0 THEN
 ROLLBACK;
END IF

to

SELECT SUM(credit) INTO v_credit FROM users WHERE name = 'mary';
IF (v_credit) < 0 THEN
 ROLLBACK;
END IF

предполагая, что v_credit-это переменная, определенная ранее. IMHO, Postgre предполагает, что запрос SELECT возвращает более одного результата, хотя вы уверены, что он уникален. Поэтому я думаю, что вы можете попытаться сначала назначить значение переменной.


Если вы хотите избежать, если вы можете переписать свой код как:

BEGIN;

    INSERT INTO movements (from, to, import)    
    SELECT 'mary', 'steve', CASE credit < 600 WHEN TRUE THEN 0 ELSE 600 END;

    UPDATE users SET credit = credit - CASE credit < 600 WHEN TRUE THEN 0 ELSE 600 END    
    WHERE name = 'mary';

    UPDATE users u SET u.credit = u.credit + CASE v.credit < 600 WHEN TRUE THEN 0 ELSE 600 END    
    FROM users v    
    WHERE u.name = 'steve' and v.name = 'mary'

COMMIT;

Да, это глупо :) .


подобно Microsoft SQL и T/SQL, вы должны иметь возможность смешивать обычный SQL с PL / pgSQL, если они находятся в правильной последовательности. Вот пример, где последовательность имеет значение в смешанном SQL / PL, хранящемся proc:

вы не можете обернуть условные операторы внутри курсора-вы должны поставить курсор внутри условного оператора. Если вы сделаете последовательность наоборот, вы получите ту же ошибку, что и раньше, ' ERROR: syntax error at или near "Если":

CREATE OR REPLACE FUNCTION getSubsystemFaultListCount(_bunoid integer, _subsystem text, _starttime timestamp without time zone, _stoptime timestamp without time zone)
      RETURNS refcursor AS
    $BODY$
    DECLARE mycurs refcursor;
    BEGIN 
        IF _subsystem = 'ALL' THEN
            OPEN mycurs FOR
            SELECT  count(*), fs_fault.faultcode, fs_fault.downloadtime
            FROM    fs_fault
            WHERE   fs_fault.bunoid = _bunoid
                AND fs_fault.statusid IN(2, 4)
                AND fs_fault.downloadtime BETWEEN _starttime AND _stoptime
            GROUP BY fs_fault.faultcode, fs_fault.downloadtime;
            RETURN mycurs;
        ELSE
            OPEN mycurs FOR
            SELECT  count(*), fs_fault.faultcode, fs_fault.downloadtime
            FROM    fs_fault
            WHERE   fs_fault.bunoid = _bunoid
                AND fs_fault.subsystemid 
                    IN(SELECT id FROM fs_subsystem WHERE type = _subsystem)
                AND fs_fault.statusid IN(2, 4)
                AND fs_fault.downloadtime BETWEEN _starttime AND _stoptime
            GROUP BY fs_fault.faultcode, fs_fault.downloadtime;
            RETURN mycurs;
        END IF;

    END;
    $BODY$

Я новичок в PostGresSQL; эта функция является просто примером.