Синтаксическая ошибка PostgreSQL «IF»
-
03-07-2019 - |
Вопрос
Я новичок в 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;эта функция является лишь примером.