Im writing a psql function. I want to do a concat between two variables inside psql.
and im getting syntax_error.
Let's notice that date_contract is of type date.
Thank you Who can help me
declare
result_table regclass := $$public.contract$$||text;
time_now time
BEGIN
execute $$SELECT MIN(date_contract) FROM $$||result_table INTO date_;
execute $$SELECT CURRENT_TIMESTAMP::time FROM $$||result_table INTO time_now;
execute $$
INSERT INTO $$||result_table||$$
(id, dat_beg_contract, dat_end_contract,date_contract, long_c)
SELECT id, dat_beg_contract, dat_end_contract, sum(extract(epoch from (least(s.dat_beg_contract, gs.date_contract||time_ + interval '1 day')::timestamp -
greatest(s.dat_beg_contract, gs.date_contract)
)
) / 60) as long_c
$$;
END;
This code block might give you an idea of how to concatenate variables
DO $$
DECLARE
rec1 text;rec2 text;
BEGIN
EXECUTE 'SELECT ''foo'' ' INTO rec1;
EXECUTE 'SELECT ''bar'' 'INTO rec2;
RAISE NOTICE 'Option 1 %, Opiton 2: %', rec1||rec2, rec1||' '||rec2 ;
END; $$ LANGUAGE plpgsql;
NOTICE: Option 1 foobar, Opiton 2: foo bar
EDIT Returning a query with a function
CREATE TABLE tab (id int);
INSERT INTO tab VALUES (100),(42);
CREATE OR REPLACE FUNCTION myfunc (table_name TEXT)
RETURNS TABLE (res int) AS $$
DECLARE v1 int; v2 int;
BEGIN
EXECUTE 'SELECT max(id) FROM '||table_name INTO v1;
EXECUTE 'SELECT min(id) FROM '||table_name INTO v2;
RETURN QUERY EXECUTE 'SELECT ' || v1 || v2 ;
END;
$$ LANGUAGE plpgsql;
SELECT myfunc('tab');
myfunc
--------
10042
EDIT 2 Example concatenating timestamp and integer
CREATE TABLE tab (id int);
INSERT INTO tab VALUES (100),(42);
CREATE OR REPLACE FUNCTION myfunc (table_name TEXT)
RETURNS TABLE (res text) AS $$
DECLARE v1 int; v2 timestamp;
BEGIN
EXECUTE 'SELECT min(id) FROM '||table_name INTO v1;
EXECUTE 'SELECT CURRENT_TIMESTAMP' INTO v2;
RETURN QUERY EXECUTE 'SELECT ' || quote_literal(v1 || ' - ' ||v2) ;
END;
$$ LANGUAGE plpgsql;
SELECT myfunc('tab');
EXECUTE 'SELECT min(id) FROM '||table_name INTO v1;
EXECUTE 'SELECT CURRENT_TIMESTAMP' INTO v2;
RETURN QUERY EXECUTE 'SELECT ' || quote_literal(v1::text || ' - ' ||v2) ;
END;
$$ LANGUAGE plpgsql;
SELECT myfunc('tab');
myfunc
--------------------------------
42 - 2021-02-02 15:54:24.24179
(1 Zeile)
EDIT 3 let me know if this works, so that I can clean the answer
CREATE TABLE tab (date_contract date);
INSERT INTO tab VALUES (current_date+7),(current_date);
CREATE OR REPLACE FUNCTION myfunc (table_name TEXT)
RETURNS TABLE (date_contract date, col_new text) AS $$
DECLARE date_ date;
BEGIN
EXECUTE 'SELECT min(date_contract) FROM '||table_name INTO date_;
RETURN QUERY EXECUTE 'SELECT date_contract,'|| quote_literal(date_|| ' ' ||current_time) ||' FROM ' || table_name;
END;
$$ LANGUAGE plpgsql;
SELECT * FROM myfunc('tab');
date_contract | col_new
---------------+-------------------------------
2021-02-09 | 2021-02-02 16:29:49.013344+01
2021-02-02 | 2021-02-02 16:29:49.013344+01
(2 Zeilen)
Related
I have developed a function to UNION ALL tables from a list of table names (a table called tablelist below) inspired by this SO post.
The initial function just returns a selection, but now I'd like to write a new table with a name taken from a parameter new_table_name.
I'm struggling with the syntax to insert the parameter into the DROP TABLE AND CREATE TABLE statements. Here's one of the attempts which returns ERROR: mismatched parentheses at or near ";"
DROP FUNCTION IF EXISTS f_multi_union(text);
CREATE OR REPLACE FUNCTION f_multi_union(new_tab_name text)
RETURNS Table (my_id int, metric double precision, geom geometry)
LANGUAGE plpgsql AS
$func$
BEGIN
RETURN QUERY EXECUTE
(
DROP TABLE IF EXISTS working.'' || new_tab_name || '';
CREATE TABLE working.'' || new_tab_name || '' AS (
SELECT string_agg(format('SELECT * FROM %s', tbl), ' UNION ALL ')
FROM (SELECT tbl FROM working.tablelist) sub
)
);
END
$func$;
Something like this?
DROP FUNCTION IF EXISTS f_multi_union(text);
CREATE OR REPLACE FUNCTION f_multi_union(new_tab_name text)
RETURNS void -- nothing to return
LANGUAGE plpgsql AS
$func$
DECLARE
_sql TEXT;
BEGIN
_sql := format('DROP TABLE IF EXISTS working.%I;', new_tab_name); -- avoid SQL injection
EXECUTE _sql;
_sql := 'SELECT string_agg(format(''SELECT * FROM %I'', tbl), '' UNION ALL '')
FROM (SELECT tbl FROM working.tablelist) sub;';
EXECUTE _sql
INTO _sql; -- overwrite current _sql content
_sql := format('CREATE TABLE working.%I AS %s;', new_tab_name, _sql);
EXECUTE _sql;
END
$func$;
I would replace the * in the SELECT statement with the columns that you need.
I would like to check if a table is empty, and if it is, I would like drop it. I know this little function doesn't seem as a useful thing by itself, but I have a much longer function, so this is just the main part.
CREATE OR REPLACE FUNCTION public.cl_tbl(t_name character varying)
RETURNS void AS
$BODY$
DECLARE
rownum int;
BEGIN
SELECT COUNT(*) INTO rownum FROM format('myschema.%I',t_name);
IF rownum = 0 then
EXECUTE format('DROP TABLE myschema.%I',t_name);
END IF;
RETURN;
END;
$BODY$
LANGUAGE plpgsql VOLATILE
My problem is, that the line
SELECT COUNT(*) INTO rownum FROM format('myschema.%I',t_name);
doesn't returns 0 if the table is empty, instead it returns 1 as the number of rows of the selection.
| count(bigint)
--------------------
1 | 0
I've tried this as well:
rownum := SELECT COUNT(*) FROM format('myschema.%I',t_name);
but the result is the same. How could I pass the real number of the rows of a given table?
You can use EXISTS() - SELECT EXISTS(SELECT * FROM table_name).
CREATE OR REPLACE FUNCTION public.cl_tbl(t_name character varying)
RETURNS void AS
$BODY$
DECLARE
x BOOLEAN;
BEGIN
EXECUTE format('select exists (select * from myschema.%I) t', t_name) INTO x;
IF x = False then
EXECUTE format('DROP TABLE myschema.%I',t_name);
END IF;
RETURN;
END;
$BODY$
LANGUAGE plpgsql VOLATILE
Try using EXECUTE:
CREATE OR REPLACE FUNCTION public.cl_tbl(t_name character varying)
RETURNS void AS
$BODY$
DECLARE
rownum int;
BEGIN
EXECUTE format('select count(*) from %I', t_name) into rownum;
IF rownum = 0 then
EXECUTE format('DROP TABLE %I',t_name);
END IF;
RETURN;
END;
$BODY$
LANGUAGE plpgsql VOLATILE
;
How can I get select (table_name, table_name.age)?
I need to get values from column 'age' from all tables having this column/
I have this function
CREATE OR REPLACE FUNCTION union_all_tables()
RETURNS TABLE
(
age bigint
) AS
$$
DECLARE
dynamic_query text = '';
r_row record;
BEGIN
FOR r_row IN SELECT table_schema || '.' || table_name qualified_table_name
FROM information_schema.COLUMNS
WHERE column_name = 'age'
LOOP
dynamic_query := dynamic_query || format('UNION SELECT ' ||
'age ' ||
'FROM %s ',r_row.qualified_table_name) || E'\n'; -- adding new line for pretty print, it is not necessary
END LOOP;
dynamic_query := SUBSTRING(dynamic_query, 7) || ';';
RAISE NOTICE 'Union all tables in staging, executing statement: %', dynamic_query;
RETURN QUERY EXECUTE dynamic_query;
END;
$$
LANGUAGE plpgsql;
You don't need to generate a single huge UNION statement. If you use RETURN QUERY the result of that query is appended to the overall result of the function every time you use it.
When dealing with dynamic SQL you should also use format() to properly deal with identifiers.
Your function can be simplified to:
CREATE OR REPLACE FUNCTION union_all_tables()
RETURNS TABLE (table_schema text, table_name text, age bigint)
AS
$$
DECLARE
dynamic_query text = '';
r_row record;
BEGIN
FOR r_row IN SELECT c.table_schema, c.table_name
FROM information_schema.columns c
WHERE c.column_name = 'age'
LOOP
dynamic_query := format(
'select %L as table_schema, %L as table_name, age from %I.%I',
r_row.table_schema, r_row.table_name,
r_row.table_schema, r_row.table_name);
RETURN QUERY EXECUTE dynamic_query;
END LOOP;
END;
$$
LANGUAGE plpgsql;
Note that the whole function will fail if there is (at least) one table where the age column is not a bigint.
Hello I am having trouble querying when I have apostrophe in my where clause in postgresql using pgpsql function, I know that manually I could do something like:
select 'author''s'
however my word is stored in a variable, here is my function:
CREATE OR REPLACE FUNCTION public.fn_inserir_doc(caminho_arqv text, conteudo text)
RETURNS void
LANGUAGE plpgsql
AS $function$
declare
conteudo_array text array;
palavra text;
begin
execute 'insert into documento(caminho)
select ''' || caminho_arqv || '''
where not exists(select id
from documento
where caminho='''||caminho_arqv||''')';
conteudo_array := regexp_split_to_array(conteudo, E'\\s+');
FOREACH palavra in array conteudo_array
loop
if length(palavra) >=3 then
raise notice 'palavra: %', palavra;
execute 'insert into termo(descricao)
select ''' || palavra || '''
where not exists(
select id from termo
where descricao='''||palavra||''')';
execute 'insert into documento_termo(id_termo, id_documento, frequencia)
select t.id, d.id, 1
from termo t
cross join documento d
where t.descricao = '''|| palavra ||'''
and d.caminho = '''|| caminho_arqv ||'''
on conflict (id_termo, id_documento) do update set frequencia = documento_termo.frequencia + 1;';
end if;
end loop;
end;
$function$
The following sample is the one that has the problem:
select id from termo
where descricao='''||palavra||'''
because palavra contains single quote
Use dollar quoting and the function format(). Example:
create or replace function test(str text)
returns setof text language plpgsql as $$
begin
-- instead of this:
-- return query execute 'select '''||str||'''::text';
-- use:
return query execute format(
$fmt$
select %L::text
$fmt$, str);
end $$;
select * from test('O''Brian');
test
---------
O'Brian
(1 row)
DECLARE
alltables record;
table_all varchar;
BEGIN
for alltables in select distinct table_name , column_name
from information_schema.colunms
loop
table_all = alltables.table_name;
raise notice 'TAB_Name:% , table_all;
end loop;
return table_all;
In here, I can see all tables in (raise notice 'TAB_Name:% , table_all;) message tab in PgAdmin
but Data output tab (return table_all;) return only one column
How can I show all the tables in the data output tab?
I am not sure, if I understand to your query. You wont to write table function probably.
CREATE OR REPLACE FUNCTION xxx
RETURNS TABLE(table_name text, column_name text)
AS $$
BEGIN
FOR table_name, column_name IN
SELECT c.table_name, c.column_name
FROM information_schema.columns
LOOP
RETURN NEXT;
END LOOP;
RETURN;
END;
$$ LANGUAGE plpgsql;
or little bit simply and little bit faster
CREATE OR REPLACE FUNCTION xxx
RETURNS TABLE(table_name text, column_name text)
AS $$
BEGIN
RETURN QUERY
SELECT c.table_name, c.column_name
FROM information_schema.columns
RETURN;
END;
$$ LANGUAGE plpgsql;
you can call it
SELECT * FROM xxx();