在 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.
我正在尝试使用触发器将最后插入的行从 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.