我想在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();
答案 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中)。您应该从引用用户表的订单表中声明一个外键,这同样可以防止删除,而且效率可能更高。