触发器功能,用于从同一个表中删除某些行

时间:2014-03-27 19:39:30

标签: sql function postgresql triggers plpgsql

我试图在Postgres中创建一个Trigger / Function,它会在插入表时检查具有相同内容的其他成员是否已经有另一个帖子。 如果有帖子,此功能将不会插入新的并保持表格不变。否则,它将被添加。

到目前为止,触发器和函数看起来像:

触发:

CREATE TRIGGER isPostUnique 
AFTER INSERT ON posts 
FOR EACH ROW
EXECUTE PROCEDURE deletePost();

功能:

CREATE FUNCTION deletePost() RETURNS TRIGGER AS $isPostUnique$
BEGIN
IF (EXISTS (SELECT * FROM posts p1, posts p2 
   WHERE (p1.userID <> p2.userID) 
   AND (p1.content LIKE p2.content)))
  THEN
    DELETE FROM NEW WHERE (posts.postID = NEW.postID);
  RETURN NEW;
END IF;
END;
$isPostUnique$ LANGUAGE plpgsql;

添加函数和触发器没有任何错误,但是当我尝试运行以下查询来测试它时:INSERT INTO posts VALUES (7, 3, 'test redundant post', 10, 1);我收到此错误

ERROR:  relation "new" does not exist
LINE 1: DELETE FROM NEW WHERE (posts.postID = NEW.postID)
                    ^
QUERY:  DELETE FROM NEW WHERE (posts.postID = NEW.postID)
CONTEXT:  PL/pgSQL function dp() line 7 at SQL statement

我知道你不能使用&#39; NEW&#39;在FOR EACH ROW插入,但我不知道如何实现这一点。

1 个答案:

答案 0 :(得分:2)

更新了更新问题的答案

当然,您可以在NEW触发器功能中使用FOR EACH ROW。你无法指导DELETE语句。它是行类型(data type HeapTuple to be precise),而不是表格。

如果已经存在相同的内容,中止 INSERT 静默(无异常)...

CREATE FUNCTION deletePost()
  RETURNS TRIGGER AS
$func$
BEGIN

IF EXISTS (
   SELECT 1
   FROM   posts p
   WHERE  p.content = NEW.content
   -- AND p.userID <> NEW.userID  -- I doubt you need this, too?
   ) THEN

    RETURN NULL;  -- cancel INSERT
ELSE
    RETURN NEW;   -- go ahead
END IF;

END
$func$ LANGUAGE plpgsql;

当然这只适用于触发......

...
BEFORE INSERT ON posts
...

唯一索引

UNIQUE constraint或唯一索引(几乎相同的效果)可能是一个更好的解决方案:

CREATE UNIQUE INDEX posts_content_uni_idx (content);

在尝试插入重复值时会引发异常。无需触发。
它还提供了非常需要的索引来加快速度。