Jos*_*ose 4 sql postgresql triggers plpgsql unique-constraint
我正在尝试检查将要插入系统的房间在该日期是否已经租用。我已经考虑过计算与房间号和日期匹配的行,然后回滚事务。但是我收到以下错误,即使我已经更改了代码以引发用户定义的异常:
Run Code Online (Sandbox Code Playgroud)ERROR: cannot begin/end transactions in PL/pgSQL HINT: Use a BEGIN block with an EXCEPTION clause instead. CONTEXT: PL/pgSQL function "checkRoom"() line 17 at SQL statement
CREATE OR REPLACE FUNCTION "checkRoom"() RETURNS TRIGGER AS
$BODY$
DECLARE
counter integer;
BEGIN
SELECT COUNT("num_sesion")
FROM "Sesion"
INTO counter
WHERE "Room_Name"=NEW."Room_Name" AND "Date"=NEW."Date";
IF (counter> 0) THEN -- Probably counter>1 as it's triggered after the transaction..
raise notice 'THERE'S A ROOM ALREADY!!';
raise exception 'The room is rented at that date';
END IF;
RETURN new;
EXCEPTION
WHEN raise_exception THEN
ROLLBACK TRANSACTION;
RETURN new;
END;$BODY$
LANGUAGE plpgsql VOLATILE NOT LEAKPROOF;
Run Code Online (Sandbox Code Playgroud)
然后我创建触发器:
CREATE TRIGGER "roomOcupied" AFTER INSERT OR UPDATE OF "Room_Name", "Date"
ON "Sesion" FOR EACH ROW
EXECUTE PROCEDURE "checkRoom"();
Run Code Online (Sandbox Code Playgroud)
从我上次使用 SQL 到现在已经 2 年了,plsql 和 plpgsql 之间的变化让我很抓狂。
您的触发器功能有几个问题:
使用IF EXISTS (...) THEN而不是计算所有出现的次数。更快,更简单。看:
触发函数可以只返回. 仅与调用的触发器相关。手册:AFTER INSERT OR UPDATENULLRETURN NEWBEFORE
操作后触发的行级触发器的返回值将被忽略,因此它们可以返回
NULL.
不平衡的单引号。
正如@Pavel 解释的那样,您无法从 plpgsql 函数中控制事务。任何未处理的异常都会强制您的整个事务自动回滚。所以,只需删除EXCEPTION块。
你的假设触发器重写:
CREATE OR REPLACE FUNCTION check_room()
RETURNS TRIGGER AS
$func$
BEGIN
IF EXISTS (
SELECT FROM "Sesion" -- are you sure it's not "Session"?
WHERE "Room_Name" = NEW."Room_Name"
AND "Date" = NEW."Date") THEN
RAISE EXCEPTION 'The room is rented at that date';
END IF;
RETURN NULL;
END
$func$ LANGUAGE plpgsql;
Run Code Online (Sandbox Code Playgroud)
一个BEFORE触发更有意义。
但是aUNIQUE INDEX ON ("Room_Name", "Date")会做同样的事情,更有效。然后,任何违反的行都会引发重复键异常并回滚事务(除非被捕获和处理)。在现代 Postgres 中,您可以INSERT使用INSERT ... ON CONFLICT .... 看:
高级用法:
PostgreSQL 处理错误的方式与其他数据库显着不同。任何未处理的错误都会向用户提出。在 PL/pgSQL 中,您可以捕获任何异常,也可以引发任何异常,但无法显式控制事务。任何 PostgreSQL 语句都在事务内部执行(函数也是如此)。当任何未处理的异常到达顶部时,最外层的事务会自动中断。
你能做什么:
BEGIN
IF CURRENT_USER <> 'Admin' THEN
RAISE EXCEPTION 'missing admin rights';
END IF;
RETURN NEW;
END;
Run Code Online (Sandbox Code Playgroud)
BEGIN
BEGIN -- start of protected section
-- do some, what can be stopped by exception
EXCEPTION WHEN divide_by_zero THEN
-- exception handler;
RAISE WARNING 'I was here';
-- should ignore
EXCEPTION WHEN others THEN
-- any unexpected exception
RAISE WARNING 'some unexpected issue';
RAISE; -- forward exception'
END;Run Code Online (Sandbox Code Playgroud)
没有其他可能性 - 所以在 PL/pgSQL 中编写应用程序非常简单,但与 PL/SQL 或 TSQL 不同。
| 归档时间: |
|
| 查看次数: |
9391 次 |
| 最近记录: |