【问题标题】:How to create a trigger on insert in postgresql to delete records that have same column values as the new records inserted如何在 postgresql 中创建插入触发器以删除与插入的新记录具有相同列值的记录
【发布时间】:2014-11-10 14:39:31
【问题描述】:

我在 postgresql (v9.3) 中有一个数据库,我总是在批处理过程中添加记录(通过 ogr2ogr 函数)。该批次由具有相同邮政编码的记录组成,这些记录存储在表“location”的“postal_code”列中(例如:location.postal_code = “90210”)。我想创建一个触发器,每次将批次插入数据库时​​,首先检查是否存在具有相同邮政编码的“旧”记录。如果它们存在,我想删除它们。如果它们不存在,则插入语句直接执行。

我曾想过使用带有“before insert”和“for each statement”的触发器,但“for each statement”阻止我使用“old”和“new”关键字。另外,我读到您不能在表上使用删除函数,而触发器在同一个表上具有“插入前”。关于如何做到这一点的任何想法?

注意:应删除先前批量插入过程中具有相同邮政编码的所有记录。例如:我在 2014 年 1 月 1 日插入了带有邮政编码“90210”的批次 #1,现在我有一个具有相同邮政编码的批次 #2,要在 2014 年 1 月 31 日插入。批次#1 中的所有记录都应该被删除,批次#2 中的所有记录都应该插入到数据库中。批次#2 可以比批次#1 有更多的记录或更少的记录,这就是为什么我认为我需要在插入批次#2 之前删除批次#1 的所有记录。

【问题讨论】:

  • 您可以删除表上before insert 触发器中的行。此外,您确实需要for each row,因为您需要检查每个插入的邮政编码。
  • 如果已经存在具有相同postal_code 的记录怎么办?应该删除它们并插入新记录,还是新插入失败并保持旧记录完好无损?
  • 应删除之前批量插入过程中具有相同邮政编码的所有记录。例如:我在 2014 年 1 月 1 日插入了带有邮政编码“90210”的批次 #1,现在我有一个具有相同邮政编码的批次 #2,要在 2014 年 1 月 31 日插入。批次#1 中的所有记录都应删除,批次#2 中的所有记录应插入数据库

标签: database postgresql triggers sql-insert sql-delete


【解决方案1】:
CREATE FUNCTION delete_duplicate_postal_code() RETURNS "trigger" AS $$
BEGIN
  DELETE FROM batch WHERE postal_code = NEW.postal_code 
      AND (now() - batch.import_timestamp > INTERVAL '5 minutes');
  RETURN NEW;
END;
$$ LANGUAGE 'plpgsql' VOLATILE;

CREATE TRIGGER
  delete_duplicate_postal_code
BEFORE INSERT ON
  batch
FOR EACH ROW EXECUTE PROCEDURE
  delete_duplicate_postal_code();

【讨论】:

  • 您的解决方案运行良好,只是它删除了我的批次#2 插入的所有行,最后一个除外!例如:在 2014 年 1 月 1 日插入带有邮政编码“90210”的批次#1,然后我想在 2014 年 2 月 2 日插入具有相同邮政编码的批次#2。执行“for each row”意味着在插入batch#2 row#1 之后,触发器启动并在插入batch#2 row#2 之前删除该行...我已经编辑了您的代码以在“ where”子句检查“现在”与插入行的时间之间的时间差(我的数据库中有此信息)。
  • 您也可以依赖事务 ID - txid_current(),以防这些插入作为一个事务执行。或者定义一些其他标准来联合这些 5 minutes 插入。
【解决方案2】:

这也称为“upsert”(“update”或“insert”的缩写)。一个 UPSERT(stuff) 命令实际上正在 Postgres 中工作,所以最终这种触发器将是一种悲观,但现在:

CREATE upsert() RETURNS TRIGGER LANGUAGE plpgsql AS
$$
BEGIN
  IF OLD.postal_code = NEW.postal_code
    THEN NEW.some_info = OLD.some_info;
  END IF;
  RETURN NEW;
END;
$$;

这非常接近,但我有一段时间没写过,所以我可能有点离题了。

这是一个非常有用的资源:@​​987654321@

Postgres 是少数几个其文档远远超过大多数商业产品的开源项目之一。如果您还没有阅读它们阅读它们。您不仅会了解 Postgres,还将了解一种不同的思维方式,这可能会改变您对数据的基本看法(并且无意中消除了对大多数触发器的需求)。

【讨论】:

    猜你喜欢
    • 2014-02-09
    • 2015-11-11
    • 1970-01-01
    • 1970-01-01
    • 2013-10-05
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多