sql - 触发错误时回滚事务

标签 sql postgresql triggers plpgsql unique-constraint

我正在尝试检查将要插入系统的房间在那个日期是否已经出租。我已经计算了匹配房间号和日期的行,然后回滚事务。但是我收到以下错误,即使我更改了代码以引发用户定义的异常:

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;

然后我创建触发器:

CREATE TRIGGER "roomOcupied" AFTER INSERT OR UPDATE OF "Room_Name", "Date"
ON "Sesion" FOR EACH ROW
EXECUTE PROCEDURE "checkRoom"();

距离我上次接触 SQL 已经 2 年了,plsql 和 plpgsql 之间的变化让我抓狂。

最佳答案

触发函数的几个问题:

  • 使用 IF EXISTS (...) THEN而不是计算所有出现的次数。更快,更简单。见:

  • 触发函数 AFTER INSERT OR UPDATE 可以只返回 NULLRETURN NEW 仅与名为 BEFORE 的触发器相关。 The manual :

    The return value is ignored for row-level triggers fired after an operation, and so they can return NULL.

  • 不平衡的单引号。

  • 作为@Pavel explained ,您无法从 plpgsql 函数中控制事务。任何未处理的异常都会强制您的整个事务自动回滚。因此,只需删除 EXCEPTION block 。

您的假设触发器已重写:

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;

BEFORE 触发器更有意义。

但是 UNIQUE INDEX ON ("Room_Name", "Date") 会做同样的事情,而且效率更高。然后,任何违反的行都会引发重复键异常并回滚事务(除非被捕获和处理)。在现代 Postgres 中,您可以选择使用 INSERT ... ON CONFLICT ... 跳过或转移此类 INSERT 尝试。见:

高级用法:

关于sql - 触发错误时回滚事务,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/16694957/

相关文章:

mysql - 如何在 MySQL 触发器中创建复杂 IF 条件

sql - 触发器中的SQL ORACLE错误

mysql - SQL:ERD 图 - 数据冗余。

mysql - 根据某种条件查询消除重复记录

php - 在 2 个或更多表上使用 SELECT

postgresql - 使用具有相同 Flask-SQLAlchemy 模型的多个 POSTGRES 数据库和模式

mysql - 如何根据列选择有限行

ruby-on-rails - 迁移期间未定义的方法 'bool' (Rails Heroku Postgres)

java - 将 SQL 解析为 sql builder

Mysql trigger on Delete to multiple tables (同样报错1235)