如何更改SQL Server而不是删除PostgreSQL触发器

时间:2019-06-29 18:19:45

标签: postgresql database-migration plpgsql database-trigger

我想在PostgreSQL中创建与SQL Server中相同的触发器。

我尝试将代码更改为可运行的功能,但出现了很多错误,但未指明错误之处,但以某种方式设法更改了可以运行的代码,但是调用触发器后却出现了错误:

  

旧的关系不存在

SQL Server触发器:

CREATE TRIGGER DeleteUser 
ON users
INSTEAD OF DELETE
AS
BEGIN
    IF EXISTS (SELECT * 
               FROM deleted d
               LEFT JOIN orders as o on o.user_id = d.id
               WHERE o.id IS NOT NULL)
    BEGIN
        ROLLBACK
        RAISERROR('Cannot delete this record: user already ordered something',16,1)
    END
    ELSE
    BEGIN
        DELETE FROM users
        WHERE EXISTS (SELECT * FROM deleted d WHERE d.id = users.id)

        PRINT('Deleted!')
    END
END
GO

适用于Postgres的代码:

功能:

CREATE FUNCTION delete_user()
RETURNS TRIGGER
AS $$
BEGIN
IF EXISTS (
    SELECT * 
    FROM old d
    LEFT JOIN orders as o on o.user_id = d.id
    where o.id is not null
    ) THEN
    RAISE EXCEPTION 'Cannot delete this record: user already ordered something';
ELSE
      DELETE FROM users
      WHERE EXISTS (Select * from deleted d where d.id = users.id);
      RAISE NOTICE 'Deleted!';
END IF;
END;
$$
LANGUAGE plpgsql;

触发:

CREATE TRIGGER deletion_of_user
    BEFORE DELETE
    ON public.users
    FOR EACH ROW
    EXECUTE PROCEDURE public.delete_user();

1 个答案:

答案 0 :(得分:2)

您无需在触发代码中删除。因为它是before触发器,所以仅返回old记录就足以进行删除。

您创建了行级别触发器(SQL Server没有此触发器),因此old记录仅是一行,您无法从中选择。只需在SELECT语句的WHERE子句中使用它即可。

CREATE FUNCTION delete_user()
RETURNS TRIGGER
AS $$
BEGIN
IF EXISTS (
    SELECT * 
    FROM orders as o 
    where o.user_id = old.id; --<< no need for a join
    ) THEN
    RAISE EXCEPTION 'Cannot delete this record: user already ordered something';
ELSE
    RAISE NOTICE 'Deleted!';
    return old; --<< tell Postgres to continue with the delete
END IF;
END;
$$
LANGUAGE plpgsql;

但是(错误地)为此使用触发器是错误的方法(在Postgres中以及在SQL Server中)。您应该从引用用户表的订单表中声明一个外键,这同样可以防止删除,而且效率可能更高。