【问题标题】:Trigger to delete rows from related tables before deleting rows from actual table在从实际表中删除行之前触发从相关表中删除行
【发布时间】:2013-11-17 19:29:19
【问题描述】:

我有以下表格:

CREATE TABLE QUESTION(
id varchar(10) NOT NULL PRIMARY KEY,
que_type numeric(1));

CREATE TABLE ESSAY(
que_id varchar(10) NOT NULL PRIMARY KEY,
ans varchar(2000),
FOREIGN KEY (que_id) REFERENCES QUESTION (id));

CREATE TABLE TFFB(
que_id varchar(10) NOT NULL PRIMARY KEY,
ans varchar(50),
FOREIGN KEY (que_id) REFERENCES QUESTION (id));

CREATE TABLE MCQ(
que_id varchar(10) NOT NULL PRIMARY KEY,
ans varchar(200),
FOREIGN KEY (que_id) REFERENCES QUESTION (id));

并尝试创建触发器,以便当我从主表中删除时,它将从其他表中删除相关行:

CREATE OR REPLACE FUNCTION delete_question()
RETURNS trigger AS $delete_question$
DECLARE
    BEGIN
    IF ( (OLD).que_type = '1' ) THEN
       IF EXISTS (SELECT 1 FROM mcq WHERE person_id = (OLD).id) THEN
          DELETE FROM mcq WHERE que_id='(OLD).id';
       END IF;
    ELSIF ( (OLD).que_type = '2' OR OLD.que_type = '3' ) THEN
       IF EXISTS (SELECT 1 FROM tffb WHERE person_id = (OLD).id) THEN
          DELETE FROM tffb WHERE que_id='(OLD).id';
       END IF;
    ELSIF ( (OLD).que_type = '4' ) THEN
       IF EXISTS (SELECT 1 FROM essay WHERE person_id = (OLD).id) THEN
          DELETE FROM essay WHERE que_id='(OLD).id';
       END IF;
    END IF;
    RETURN NULL;
    END;
    $delete_question$ LANGUAGE plpgsql;

    CREATE TRIGGER delete_question
    BEFORE DELETE ON question
        FOR EACH ROW EXECUTE PROCEDURE delete_question();

当我从question 中删除数据时,该行会消失一段时间。但是当我刷新时,它仍然存在。
我尝试输入RETURN OLD;,但由于约束关系而失败。 这有什么问题?

【问题讨论】:

  • 外键使用ON DELETE CASCADE有什么问题?

标签: sql postgresql triggers plpgsql sql-delete


【解决方案1】:

关于触发功能的更多建议:

CREATE OR REPLACE FUNCTION delete_question()
  RETURNS trigger AS
$func$
BEGIN

CASE OLD.que_type
WHEN 1 THEN
    DELETE FROM mcq   WHERE que_id=OLD.id;
WHEN 2, 3 THEN
    DELETE FROM tffb  WHERE que_id=OLD.id;
WHEN 4 THEN
    DELETE FROM essay WHERE que_id=OLD.id;
-- ELSE
--      Do something?
END CASE;

RETURN OLD;

END
$func$ LANGUAGE plpgsql;

要点

  • 使用SELECT 语句检查是否存在会使成本翻倍。只需运行DELETE,如果没有找到匹配的行,则不会删除任何内容。

  • 在此处使用CASE 语句。更短,更快。请注意,plpgsql CASE 与 SQL CASE 语句略有不同。例如,您可以一次列出多个案例。

  • 您不需要DECLARE 关键字,除非您实际声明了变量。

另类设计

cascading deletes via foreign key 可以完全避免这个问题,就像@a_horse mentioned in the comment。我的架构布局如下所示:

CREATE TABLE question (
   question_id serial NOT NULL PRIMARY KEY
  ,que_type    int   -- this may be redundant as well
);

CREATE TABLE essay (
   que_id int NOT NULL PRIMARY KEY
              REFERNECES question(question_id) ON UPDATE CASCADE
                                               ON DELETE CASCADE
  ,ans    text
);

...

关于serial
Auto increment SQL function

【讨论】:

    【解决方案2】:

    然后我再次尝试解决它....它工作得很好。是的。

    CREATE OR REPLACE FUNCTION delete_question()
    RETURNS trigger AS $delete_question$
    DECLARE
    BEGIN
    IF ( OLD.que_type=1 ) THEN
       IF EXISTS (SELECT 1 FROM mcq WHERE que_id=OLD.id) THEN
          DELETE FROM mcq WHERE que_id=OLD.id;
       END IF;
    ELSIF ( OLD.que_type=2 OR OLD.que_type=3) THEN
       IF EXISTS (SELECT 1 FROM tffb WHERE que_id=OLD.id) THEN
          DELETE FROM tffb WHERE que_id=OLD.id;
       END IF;
    ELSIF ( OLD.que_type=4 ) THEN
       IF EXISTS (SELECT 1 FROM essay WHERE que_id=OLD.id) THEN
          DELETE FROM essay WHERE que_id=OLD.id;
       END IF;
    END IF;
    RETURN OLD;
    END;
    $delete_question$ LANGUAGE plpgsql;
    
    CREATE TRIGGER delete_question
    BEFORE DELETE ON question
        FOR EACH ROW EXECUTE PROCEDURE delete_question();
    

    OLD.id 甚至(OLD).id 上没有' ' 并使用RETURN OLD;

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2012-08-02
      • 1970-01-01
      相关资源
      最近更新 更多