Синтаксическая ошибка PostgreSQL «IF» - PullRequest
12 голосов
/ 29 апреля 2009

Я новичок в 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 ]

7 голосов
/ 29 апреля 2009

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

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

Кроме того, вы можете посмотреть следующую ссылку для получения дополнительной информации о том, как использовать IF ... THEN ... ELSE ... END IF; условия внутри plpgsql: ссылка .


EDIT:

Я не знаю, разрешен ли ROLLBACK в этот момент (поскольку каждая хранимая процедура уже находится в отдельной транзакции), но вы должны быть в состоянии выяснить это самостоятельно, используя обширную документацию @ 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. Все это легче усвоить.

2 голосов
/ 29 апреля 2009

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

1 голос
/ 30 апреля 2009

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

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

до

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

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

1 голос
/ 29 апреля 2009

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

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;

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

0 голосов
/ 06 апреля 2012

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

Вы не можете обернуть условные операторы внутри курсора - вы должны поместить курсор в условный оператор. Если вы выполните последовательность действий наоборот, вы получите ту же ошибку, что и раньше, «ОШИБКА: синтаксическая ошибка в или около« IF »»:

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; эта функция только пример.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...