PostgreSQL: Select string_agg into variable - postgresql

I have a string to execute with the string aggregate function within the postgresql function. Here is the following script for that.
Example:
create or replace function f(colvalue int,colnvalue varchar)
returns void as
$$
declare
sql varchar;
var varchar;
begin
sql := 'Select var:= string_agg(................) /* Error occurred here near var:= */
from tablename where cola ='|| colvalue || ' AND coln ='|| colnvalue;
raise notice '%'sql;
execute sql into var;
raise notice var;
end;
$$
language plpgsql;
Error:
ERROR: syntax error at or near ":="
Note: I want the result of string_agg into var.

Dynamic SQL can contains SQL statement only - but ":=" is a PL/pgSQL statement. Next, it is clean from your example, so it is useless there. Second issue is a SQL injection vulnerability (still this code should not work). Newer use a patter ' || varcharvar || ' for SQL used in dynamic SQL.
CREATE OR REPLACE FUNCTION f(colvalue int,colnvalue varchar)
RETURNS void AS $$
DECLARE
sql varchar;
var varchar;
BEGIN
sql := 'SELECT string_agg(..) FROM tablename WHERE cola=$1 AND coln=$2';
RAISE NOTICE '%', sql;
EXECUTE sql INTO var USING colvalue, colnvalue;
RAISE NOTICE '%', var;
END;
$$ LANGUAGE plpgsql;

Related

Argument not taking the value from Postgres function

I have a simple Postgres function where I want to take table_name as a parameter and pass it into an argument and delete the data from table by condition.
CREATE OR REPLACE FUNCTION cdc.audit_refresh(tablename text)
RETURNS integer AS
$$
BEGIN
delete from tablename where id<4;
RETURN(select 1);
END;
$$ LANGUAGE plpgsql;
select cdc.audit_refresh('cdc.adf_test');
But it throws out an error that tablename
ERROR: relation "tablename" does not exist in the delete statement.(refer snapshot)
What you want to achieve is to execute Dynamic SQL statements. You can do this with EXECUTE. See more here
CREATE OR REPLACE FUNCTION audit_refresh(tablename text)
RETURNS integer AS
$$
DECLARE
stmt TEXT;
BEGIN
stmt = 'delete from '||tablename||' where id<4;';
EXECUTE stmt;
RETURN 1;
END
$$ LANGUAGE plpgsql;

Is it possible to nest an EXECUTE statement as a source recordset in PostgreSQL?

This is the case of a dynamic _sql select passed to a function that tries to execute the query and return a JSON array with the result.
create or replace function jlist_objects_bysql (
_sql varchar
)
returns json
as $$
select
json_agg (t)
from (
execute _sql
) as t;
$$ language sql;
The validation error in PostgreSQL 12 is
psql:objects_procedures.sql:874: ERROR: syntax error at or near "t"
LINE 8: from execute _sql t;
Dynamic SQL does not work with the language sql but rather with language plpgsql.
Then, you can enlarge the dynamic query
create or replace function jlist_objects_bysql (
_sql varchar
)
returns json
as $$
declare
output json;
BEGIN
execute 'select json_agg (t) from ( ' || _sql || '
) as t;'
INTO output;
return output;
END
$$ language plpgsql;
select jlist_objects_bysql('select * from test');

Using to_jsonb(NEW) and execute

CREATE OR REPLACE FUNCTION change_trigger() RETURNS trigger AS $$
BEGIN
INSERT INTO static_table_name (content) VALUES (to_jsonb(NEW));
END;
$$ LANGUAGE 'plpgsql' SECURITY DEFINER;
↑ is working, but I'd like to have opportunity to send target table name for inserting.
So,
by the code above, I was able to use dymanic_table_name,
CREATE OR REPLACE FUNCTION change_trigger() RETURNS trigger AS $$
DECLARE
dymanic_table_name TEXT;
BEGIN
dymanic_table_name := TG_ARGV[0];
EXECUTE 'INSERT INTO ' || dymanic_table_name || ' (content) VALUES (' || to_json(NEW) || ');';
END;
$$ LANGUAGE 'plpgsql' SECURITY DEFINER;
but it fails, when try to insert result of 'to_json' function...
ERROR:
ERROR: "{"またはその近辺で構文エラー
LINE 1: ..._table (content) VALUES ({"id":43,"...
^
※ Sorry for Japanese syntax ( *´艸`)
You'll have to use dynamic SQL like this:
EXECUTE
format(
'INSERT INTO %I (content) VALUES (to_json($1))',
dymanic_table_name
)
USING NEW;

PostgreSQL: ERROR: syntax error at or near "-"

Here I need to call a function with some parameters.
Example:
Function:
create or replace function testfunction(ids int,pcname varchar)
returns void as
$$
declare
sql varchar;
qu varchar := 'tabletemp_';
begin
qu := qu ||ids ||'_'|| pcname;
sql := 'Drop view if exists '||qu;
raise info '%',sql;
execute sql;
end;
$$
language plpgsql;
Calling Function:
select testfunction(1,'abc-pc');
Error:
ERROR: syntax error at or near "-"
Drop view if exists tabletemp_1_abc-pc
^
Question: How can I pass such parameter while calling function?
You forgot to quote_ident.
sql := 'Drop view if exists '|| quote_ident(qu);
but you should preferably use format:
sql := format('Drop view if exists %I', qu || ids ||'_'|| pcname);
Try This:
create or replace function testfunction(ids int,pcname varchar)
returns void as
$$
declare
sql varchar;
qu varchar := 'tabletemp_';
begin
qu := qu ||ids ||'_'|| pcname;
sql := 'Drop view if exists "'||qu||'"';
raise info '%',sql;
execute sql;
end;
$$
language plpgsql;
Here I add double quote around table name.

PostgreSQL: How to assign "SELECT" query to variable using dblink?

Here I am trying to assign a "SELECT" query to a specific variable. The select query is retrieving rows from other database table using dblink. For example as shown below:
Example: My try
create or replace function fun(names varchar(60), id bigint) returns void as
$$
Declare
sql varchar;
Begin
sql := 'Select * from dblink'('conn','select * from tablex') /* Error occurred here */
'where name = ''' || names ||'''';
raise info '%',sql;
execute sql,'names varchar(60)',names=names;
end;
$$
Language plpgsql;
ERROR: syntax error at or near "("
You've messed up your quotimg.
You can use dollar-quoting inside the fumction too.
sql := $SQL$...$SQL$
Solution: Here is the solution
create or replace function fun(names varchar(60), id bigint) returns void as
$$
Declare
sql varchar;
Begin
sql := 'Select * from dblink(''conn','select * from tablex'')
where name = ''' || names ||'''';
raise info '%',sql;
execute sql,'names varchar(60)',names=names;
end;
$$
Language plpgsql;