I have a table called rezultz with 1 row only containing valid SQL queries like: CREATE TRIGGER ... I'm trying to execute them with this function called get_all_rezultz() but it doesn't seem to work,any ideas why?
CREATE OR REPLACE FUNCTION get_all_rezultz() RETURNS SETOF rezultz AS
$BODY$
DECLARE
r rezultz%rowtype;
BEGIN
FOR r IN
SELECT * FROM rezultz
LOOP
-- can do some processing here
RETURN QUERY EXECUTE r; -- return current row of SELECT
END LOOP;
RETURN;
END
$BODY$
LANGUAGE plpgsql;
SELECT * FROM get_all_rezultz();
Here is the error I get :
NOTICE: identifier "CREATE TRIGGER userman_if_modified_trg AFTER INSERT OR UPDATE OR DELETE ON userman FOR EACH ROW EXECUTE PROCEDURE audit.if_modified_func(); " will be truncated to "CREATE TRIGGER userman_if_modified_trg AFTER INSERT OR UPDATE O"
CONTEXT: SQL statement "("CREATE TRIGGER userman_if_modified_trg AFTER INSERT OR UPDATE OR DELETE ON userman FOR EACH ROW EXECUTE PROCEDURE audit.if_modified_func(); ")"
PL/pgSQL function get_all_rezultz() line 10 at RETURN QUERY
ERROR: syntax error at or near ""CREATE TRIGGER userman_if_modified_trg AFTER INSERT OR UPDATE OR DELETE ON userman FOR EACH ROW EXECUTE PROCEDURE audit.if_modified_func(); ""
LINE 1: ("CREATE TRIGGER userman_if_modified_trg AFTER INSERT OR UPD...
^
QUERY: ("CREATE TRIGGER userman_if_modified_trg AFTER INSERT OR UPDATE OR DELETE ON userman FOR EACH ROW EXECUTE PROCEDURE audit.if_modified_func(); ")
CONTEXT: PL/pgSQL function get_all_rezultz() line 10 at RETURN QUERY
********** Error **********
ERROR: syntax error at or near ""CREATE TRIGGER userman_if_modified_trg AFTER INSERT OR UPDATE OR DELETE ON userman FOR EACH ROW EXECUTE PROCEDURE audit.if_modified_func(); ""
SQL state: 42601
Context: PL/pgSQL function get_all_rezultz() line 10 at RETURN QUERY
The variable r is a record containing multiple columns. It's not a scalar value (e.g. a string).
So you need to use the column name in the execute statement. Assuming the column in the table is called sql_statement you need to use:
RETURN QUERY EXECUTE r.sql_statement;
However, this will still not work because the select statement stored in that table will most definitely not return a results that is SETOF rezultz it returns a SETOF mytable if the query is select * from mytable.
You would need to specify RETURNS SETOF record but then you need to specify the column names and structure of the result when calling the function.
And even then this won't work because a function still only return a single result, not multiple results from multiple queries - which will happen if rezultzcontains more then one row.
If your SQL statements aren't actually SELECT statements as you have claimed, you will need to use EXECUTE you can't use RETURN QUERY for a CREATE TRIGGER statement.
Related
I want to update the timestamp attribute 'register_updated' to the current_timestamp whenever any value is updated in the table.
This is my function
CREATE OR REPLACE FUNCTION fn_register_updated()
RETURNS trigger language plpgsql AS $$
BEGIN
UPDATE tb_register
SET register_updated = CURRENT_TIMESTAMP
WHERE (OLD.* IS DISTINCT FROM NEW.*);
RETURN NEW;
END;
$$;
CREATE TRIGGER tg_register_updated
BEFORE UPDATE
ON tb_register
FOR EACH ROW
EXECUTE PROCEDURE fn_register_updated();
But whenever I run an update on a table I receive the following error:
SQL statement "UPDATE tb_register
SET register_updated = CURRENT_TIMESTAMP"
PL/pgSQL function fn_register_updated() line 3 at SQL statement
SQL statement "UPDATE tb_register
SET register_updated = CURRENT_TIMESTAMP"
PL/pgSQL function fn_register_updated() line 3 at SQL statement
SQL statement "UPDATE tb_register
Any ideas on how to solve this?
I am struggling with the use of UPDATE within the body of the function.
Thank you,
Sample code for you:
CREATE OR REPLACE FUNCTION fn_register_updated()
RETURNS trigger
LANGUAGE plpgsql
AS $function$
begin
new.register_updated = CURRENT_TIMESTAMP;
RETURN NEW;
END;
$function$;
create trigger tg_register_updated before
update
on
tb_register for each row execute function fn_register_updated();
I'm new on PostgreSQL and I want to know why my temporary table is not dropped after a return different to return query.
I can execute this function many times without a "table already exists" error.
CREATE OR REPLACE FUNCTION test_table()
RETURNS TABLE (response JSON)
AS $$
BEGIN
CREATE TEMP TABLE temp_test_table AS SELECT * FROM Users;
RETURN QUERY SELECT '{"name": "Moises"}'::JSON;
DROP TABLE temp_test_table;
END; $$
LANGUAGE 'plpgsql';
But in this case, after the first execution, I receive a "ERROR: relation "temp_test_json" already exists".
CREATE OR REPLACE FUNCTION test_json()
RETURNS JSON
AS $$
BEGIN
CREATE TEMP TABLE temp_test_json AS SELECT * FROM Users;
RETURN '{"name": "Moises"}'::JSON;
DROP TABLE temp_test_json;
END; $$
LANGUAGE 'plpgsql';
How return query or just return affects the temporary table when is dropped?
RETURN terminates the execution of the function, so execution does not reach the DROP TABLE statement in the second function.
Contrariwise, RETURN QUERY adds rows to the function result set, but does not terminate the execution, so DROP TABLE is executed in the first function.
I trying to select query based on condition using IF ElSE in postgres. Below is my query.
DO
$do$
DECLARE res varchar(50) := 'a';
BEGIN
IF (res = 'a') THEN
SELECT "Name" FROM "TestTable";
ELSE
SELECT "ID" FROM "TestTable";
END IF;
END
$do$
but I am getting following error
ERROR: query has no destination for result data
HINT: If you want to discard the results of a SELECT, use PERFORM instead.
CONTEXT: PL/pgSQL function inline_code_block line 5 at SQL statement
What I am doing wrong here??
DO purpose is to execute anonymous code block and it doesn't return anything (it returns void, to be specific).
You can execute your SELECT statement afterwards (outside of DO block), or perform an INSERT to temporary table which you need to create beforehand (and this can be done within the block).
The function is created fine, but when I try to execute it, I get this error:
ERROR: relation "column1" does not exist
SQL state: 42P01
Context: SQL statement "ALTER TABLE COLUMN1 ADD COLUMN locationZM geography (POINTZM, 4326)"
PL/pgSQL function addlocationzm() line 6 at SQL statement
Code:
CREATE OR REPLACE FUNCTION addlocationZM()
RETURNS void AS
$$
DECLARE
COLUMN1 RECORD;
BEGIN
FOR COLUMN1 IN SELECT f_table_name FROM *schema*.geography_columns WHERE type LIKE 'Point%' LOOP
ALTER TABLE COLUMN1 ADD COLUMN locationZM geography (POINTZM, 4326);
END LOOP;
END;
$$
LANGUAGE 'plpgsql';
SELECT addlocationZM()
I'm probably just being dumb, but I've been at this for a while now and I just can't get it. The SELECT f_table_name ... statement executed on its own returns 58 rows of a single column, each of which is the name of a table in my schema. The idea of this is to create a new column, type PointZM, in each table pulled by the SELECT.
The function would work like this:
CREATE OR REPLACE FUNCTION addlocationZM()
RETURNS void AS
$func$
DECLARE
_tbl text;
BEGIN
FOR _tbl IN
SELECT f_table_name FROM myschema.geography_columns WHERE type LIKE 'Point%'
LOOP
EXECUTE
format('ALTER TABLE %I ADD COLUMN location_zm geography(POINTZM, 4326)', _tbl);
END LOOP;
END
$func$ LANGUAGE plpgsql;
Note how I use a simple text variable to simplify matters. You don't need the record to begin with.
If it's a one-time operation, use a DO command instead of creating a function:
DO
$do$
BEGIN
EXECUTE (
SELECT string_agg(
format(
'ALTER TABLE %I ADD COLUMN location_zm geography(POINTZM, 4326);'
, f_table_name)
, E'\n')
FROM myschema.geography_columns
WHERE type LIKE 'Point%'
);
END
$do$;
This is concatenating a single string comprised of all commands (separated with ;) for a single EXECUTE.
Or, especially while you are not familiar with plpgsql and dynamic SQL, just generate the commands, copy/paste the result and execute as 2nd step:
SELECT 'ALTER TABLE '
|| quote_ident(f_table_name)
|| ' ADD COLUMN locationZM geography(POINTZM, 4326);'
FROM myschema.geography_columns
WHERE type LIKE 'Point%';
(Demonstrating quote_ident() this time.)
Related:
Table name as a PostgreSQL function parameter
Aside: Unquoted CaMeL-case identifiers like locationZM or your function name addlocationZM may not be such a good idea:
Are PostgreSQL column names case-sensitive?
I have the following code in postgresql:
CREATE OR REPLACE FUNCTION update_category() RETURNS trigger AS $newProduct$
BEGIN
UPDATE category SET product_count = product_count + 1 WHERE cat_id = NEW.cat_id;
INSERT INTO notification (content, type, p_id) VALUES('new product', 1, NEW.p_id);
RETURN NEW;
END;
$newProduct$ LANGUAGE plpgsql;
CREATE TRIGGER update_cat AFTER INSERT ON product
EXECUTE PROCEDURE update_category();
And after inserting a record into product I get the error:
[2017-03-20 16:05:05] [55000] ERROR: record "new" is not assigned yet
[2017-03-20 16:05:05] Detail: The tuple structure of a not-yet-assigned record is indeterminate.
[2017-03-20 16:05:05] Where: SQL statement "UPDATE category SET product_count = product_count + 1 WHERE cat_id = NEW.cat_id"
[2017-03-20 16:05:05] PL/pgSQL function update_category() line 3 at SQL statement
I've looked around for a solution, but I only find cases where the error is because
FOR EACH STATEMENT
is being used instead of
FOR EACH ROW
Seeing as I'm simply executing the procedure once, the solution doesn't apply in my case.
Thanks for your help!
The solution was indeed to add FOR EACH ROW:
CREATE TRIGGER update_cat AFTER INSERT ON product
FOR EACH ROW EXECUTE PROCEDURE update_category();
I assumed FOR EACH ROW meant calling the procedure once for each row in product, not for each row inserted.