在 Postgres 触发器中使用 NEW 和 COPY

Using NEW and COPY in a Postgres Trigger

我正在尝试使用触发器将最后插入的行从 table 复制到 csv 文件中。

CREATE TRIGGER new_tbc_order
  AFTER INSERT
  ON trig_test
  FOR EACH ROW
  EXECUTE PROCEDURE write_last_tbc_order();



CREATE OR REPLACE FUNCTION write_last_tbc_order()
RETURNS TRIGGER 
LANGUAGE plpgsql
as $$
BEGIN
    EXECUTE 'COPY (
             select i.id, i.paid, i.no_items FROM (SELECT NEW.*) AS i 
         ) TO ''/Users/fred/Desktop/last_tbc_order.csv'' csv;' USING NEW;
    RETURN NEW;
END; $$

我已经尝试过各种形式,有或没有 EXECUTE,但我仍然遇到错误。

ERROR:  missing FROM-clause entry for table "new"
LINE 1: ...opy (select i.id, i.paid, i.no_items FROM (SELECT NEW.*) AS ...
                                                         ^

只是无法访问新数据。

我哪里错了?

我能让它工作的唯一方法是这样的:

CREATE OR REPLACE FUNCTION write_last_tbc_order()
RETURNS TRIGGER 
LANGUAGE plpgsql
as $$
BEGIN
    EXECUTE 'COPY (
             select id, paid, no_items FROM trig_test WHERE id = ' || NEW.id ||  
         ') TO ''/Users/fred/Desktop/last_tbc_order.csv'' csv;';
    RETURN NEW;
END; $$

COPY好像没有'see'的NEW记录。请注意,如果 Postgres 服务器在 /Users/fred/Desktop/ 上没有权限,则上述操作将失败,因为 COPY 作为服务器用户运行。我个人认为更好的解决方案是写信给审计 table 并定期从那里收集记录。

Adrian 的回答激发了我对实际可用的 NEW 记录进行更多试验的灵感。 像往常一样,实际答案很简单:

CREATE OR REPLACE FUNCTION write_last_tbc_order()
RETURNS TRIGGER 
AS 
$$
BEGIN
    EXECUTE 'copy (select '''||NEW.id||''','''||NEW.paid||''','''||NEW.no_items||''') 
to ''/Users/shaun/Desktop/last_tbc_order.csv'' csv;' USING NEW;
    RETURN NEW;
END; 
$$
LANGUAGE plpgsql;

因此将 NEW 记录保留在复制语句之外并在执行之前动态构建它。

这仍然需要最后的 USING NEW 部分才能使其正常工作。 还需要所有报价。

更新:

上面的代码确实需要 almost 一切都是 运行 作为 Postgres 超级用户,(正如一些评论者所提到的),这并不理想。

为了解决这个问题,您可以创建一个 PlPython 函数,如下所示:

CREATE OR REPLACE FUNCTION write_last_tbc_order() 
RETURNS TRIGGER AS
'
import os
row = str(TD["new"]["id"]) + "," + TD["new"]["paid"] + "," + str(TD["new"]["noitems"])
path = "/tmp/db-data/last_order.csv";
with open(path,"w") as o:
    os.chmod(path, 0o644)
    o.write(row)
return None
'
LANGUAGE 'plpythonu';

此函数必须以超级用户的身份创建,但它可以用于标准用户创建的触发器,并且当标准用户触发插入时,ose 触发器也可以工作。

写入文件的地方必须有postgres用户的写入权限,所以我在/tmp下创建了一个777权限的子目录

还需要在 os chmod 644 语句中添加,以使系统上的其他用户可以读取该文件。如果没有这个,文件将以 600 的权限创建。

进一步说明:

最后 Apache 不喜欢你在 /tmp 目录中设置一个虚拟目录所以最后不得不创建另一个名为 /tmp-wh 专门为此 purpose.