我是PostgreSQL的新手,我已经遇到了第一个问题..
我按照手动分步编写了一些代码来了解交易的工作原理。
为了简短起见,我创建了2个表,用户和动作:第一个是名称,电子邮件和信用列,第二个是from,to,import。
所以,我是这样尝试的:
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条款......
答案 0 :(得分:7)
正如Johannes已经说过的那样:你正在将常规SQL与存储过程语言PL / pgSQL混合使用。 Johannes提供的链接应该向您解释存储过程的概念。
我认为你是以剧本形式做的吗?一个接一个地执行一个声明?我担心您只能在存储过程或函数中执行您想要执行的操作,就像您可能称之为的那样。这是因为当您以这种方式执行语句时,每个语句都独立存在,没有关于其他语句的关系或信息。
此外,您可以查看以下链接,了解有关如何使用IF的更多信息...那么... ELSE ... END IF; plpgsql中的条件:link。
修改强>
我不知道此时是否允许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数据库管理器。学习这一切更容易。
答案 1 :(得分:2)
您似乎使用普通SQL
,但IF
语句是PostgreSQL中PL/pgSQL
过程语言的一部分。
答案 2 :(得分:1)
如果你想避免如果你可以将代码重写为:
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;
是的,这是愚蠢的:)。
答案 3 :(得分:1)
您可以尝试修改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查询返回多个结果,即使您非常确定它是唯一的。所以我认为你可以先尝试将值赋给变量。
答案 4 :(得分:0)
与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的初学者;这个函数只是一个例子。