Вопрос

Я новичок в 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.:Не зацикливайтесь на примерах функциональности, для меня это всего лишь попытка понять транзакции.а теперь пункт ЕСЛИ...

Это было полезно?

Решение

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

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

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


РЕДАКТИРОВАТЬ:

Я не знаю, разрешен ли 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;

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

Другие советы

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

Вы можете попробовать изменить часть 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 возвращает более одного результата, даже если вы абсолютно уверены, что он уникален.Поэтому я думаю, что вы могли бы попытаться заранее присвоить значение переменной.

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

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;

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

Подобно SQL и T/SQL от Microsoft, вы сможете смешивать обычный 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;эта функция является лишь примером.

Лицензировано под: CC-BY-SA с атрибуция
Не связан с StackOverflow
scroll top