每个唯一值执行一次函数

时间:2017-04-12 16:36:26

标签: postgresql function

我有两张表格,其中包含与日常业务相关的数据:

CREATE TABLE main_table (
  main_id serial,
  cola text,
  colb text,
  colc text,
  CONSTRAINT main_table_pkey PRIMARY KEY (main_id)
);

CREATE TABLE second_table (
  second_id serial,
  main_id integer,
  cold text,
  CONSTRAINT second_table_pkey PRIMARY KEY (second_id),
  CONSTRAINT second_table_fkey FOREIGN KEY (main_id)
    REFERENCES main_table (main_id) MATCH SIMPLE
    ON UPDATE NO ACTION ON DELETE NO ACTION
);

我们需要知道这些表中何时更新了某些数据,以便可以生成导出并推送给第三方。我创建了第三个表来保存更新信息:

CREATE TYPE field AS ENUM ('cola', 'colb', 'colc', 'cold');
CREATE TABLE table_updates (
  main_id int,
  field field
  updated_on date NOT NULL DEFAULT NOW(),
  CONSTRAINT table_updates_fkey FOREIGN KEY (main_id)
    REFERENCES main_table (main_id) MATCH SIMPLE
    ON UPDATE NO ACTION ON DELETE NO ACTION
);

main_table触发在table_updates次查询之前更新UPDATE,满足了跟踪四个列更新中的三个的需求。

我可以轻松地将相同类型的触发器添加到second_table,但是由于main_id不唯一,因此可以对单个main_id值执行多次函数,这是不可取的

如何创建一个函数,当更新second_table中的多行时,每main_id只执行一次?

2 个答案:

答案 0 :(得分:2)

  

如何创建一个函数,当更新second_table中的多行时,每个main_id只执行一次?

如果您的插入符号是由main_id插入的,即INSERT INTO tbl (main_id...) VALUES (main_id ...),(main_id ...),(main_id ...),您可以使用rule system触发一次INSERTUPDATE

  

对于两者都可以实现的事情,最好取决于数据库的用法。 为每个受影响的行触发一次触发器。规则会修改查询或生成其他查询。因此,如果在一个语句中影响了许多行,则发出一个额外命令的规则可能比为每一行调用的触发器更快,并且必须重新生成确定要做多次。但是,触发器方法在概念上远比规则方法简单,并且新手更容易正确。

羞涩的是,您可能还想查看正常的LISTENNOTIFY。这使您能够使用异步操作。如果那是您的事情,并且您决定通过tcn继续考虑触发器更改通知模块。

我的建议是尽可能在应用程序(数据库之外)中执行此操作。请记住,PostgreSQL temp表是会话的本地表。所以你可以让每个加载器会话做这样的事情,

BEGIN
  CREATE TEMP TABLE UNLOGGED etl_inventory;
  COPY foo FROM stdin;
  -- Are they different, if so `NOTIFY`
  -- UPSERT
COMMIT;

然后有一个守护进程在收到NOTIFY事件时将导出添加到导出队列。

答案 1 :(得分:1)

虽然Evan的answer是正确的,但我认为这个问题可以从一个例子中受益。

这是我在问题中使用示例表的规则定义:

CREATE OR REPLACE RULE update_update_table
AS ON UPDATE TO second_table
DO ALSO (
  INSERT INTO table_updates (
    main_id, field
  )
  SELECT DISTINCT OLD.main_id, 'cold'::field
  WHERE NOT EXISTS (
    SELECT TRUE
    FROM table_updates
    WHERE main_id = OLD.main_id
        AND field = 'cold'
  );
  UPDATE table_updates
  SET updated_on = NOW()
  WHERE main_id = OLD.main_id
    AND field = 'cold'
)