I'm trying to copy the last inserted row from a table into a csv file using a trigger.
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; $$
I've tried this in various incarnations, with or without EXECUTE but I'm still getting the error.
ERROR: missing FROM-clause entry for table "new"
LINE 1: ...opy (select i.id, i.paid, i.no_items FROM (SELECT NEW.*) AS ...
^
Just cannot get it to access the NEW data.
Where am I going wrong?
The only way I could get this to work is something like this:
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
does not seem to 'see' the NEW record. Be aware that the above will fail if the Postgres server does not have permissions on /Users/fred/Desktop/ as COPY
runs as the server user. Personally I think a better solution is to write to a audit table and periodically harvest the records from there.
Adrian's answer inspired me to experiment more with the NEW record where it was actually available. The actual answer, as usual, turned out to be simple-ish:
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;
Thus keeping the NEW record outside of the copy statement and building it dynamically before the execute.
This still required the USING NEW part at the end to make it work correctly. Also required all the quoting.
UPDATE:
The above code does require almost everything to be running as a Postgres Superuser, (as mentioned by several commenters), which is not ideal.
To get around this, you can create a PlPython function as follows:
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';
This function must be created as a Superuser, but it can be used in triggers created by standard users, and those triggers also work when inserts are fired by standard users.
The place to where the file is written must have write permission for the postgres user in every part of the path, so I created a subdirectory of /tmp with 777 permissions.
Also needed to add in the os chmod 644 statement to make the file readable by other users on the system. Without this, the file is created with permissions of 600.
FURTHER NOTES:
In the end Apache doesn't like you to setup a virtual directory inside the /tmp directory so in the end had to create another called /tmp-wh specifically for this purpose.
The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.