Postgresql - psql - for loop not displaying output - postgresql

The following sql file runs without error; however it does no display any output.
The file is executed with: pslq -d database -f filename.
How can this be modified to display output?
do $$
declare tn varchar ;
begin
for tn in
select tablename from pg_tables where tableowner not like 'postgres%'
loop
EXECUTE format('SELECT count(*) from %I;', tn);
end loop;
end;
$$;

The problem is that the result of a dynamic query is discarded unless you use SELECT ... INTO:
DO $$
DECLARE
tn text;
total bigint;
BEGIN
FOR tn IN
SELECT tablename FROM pg_tables WHERE tableowner NOT LIKE 'postgres%'
LOOP
EXECUTE format('SELECT count(*) from %I;', tn) INTO total;
RAISE NOTICE 'Table: % rows: %', tn, total;
END LOOP;
END;
$$;

Related

How to use a Function Parameter in a Cursor that's incorporated with Dynamic SQL in Postgres Functions?

Created this Postgres Function which is working fine, but the actual requirement is to pass the input parameter in the function to the Cursor which uses the dynamic SQL as follows,
The below is the Function
CREATE OR REPLACE FUNCTION ssp2_pcat.find_shift_dates (date_to_find date)
RETURNS void
LANGUAGE 'plpgsql'
COST 100
VOLATILE
AS $BODY$
DECLARE
C1 CURSOR FOR
SELECT TABLE_NAME, 'SELECT COUNT(*) FROM ' || TABLE_NAME || ' WHERE ' ||
COLUMN_NAME || ' = '||
'CASE WHEN ' || COLUMN_NAME || ' LIKE ' || '''%START%'''||' THEN
date_to_find ELSE date_to_find-1 END;' SQL_TEXT
FROM (
SELECT TABLE_NAME, COLUMN_NAME
FROM INFORMATION_SCHEMA.COLUMNS
WHERE TABLE_NAME IN (SELECT TABLE_NAME FROM RESET_DATES WHERE RESET_IT =
'Y') AND
UPPER(DATA_TYPE) = 'DATE'
AND (COLUMN_NAME LIKE '%START%' OR COLUMN_NAME LIKE '%END%')
AND (COLUMN_NAME NOT LIKE '%TEST%'
AND COLUMN_NAME NOT LIKE '%PCAT%'
AND COLUMN_NAME NOT LIKE '%ORDER%'
AND COLUMN_NAME NOT LIKE '%SEASON%'
AND COLUMN_NAME NOT LIKE '%_AT')
ORDER BY 1, 2) A;
END_COUNT INTEGER := 0;
START_COUNT INTEGER := 0;
TABLENAME VARCHAR(32) := 'ALFU';
l_start TIMESTAMP;
l_end TIMESTAMP;
Time_Taken VARCHAR(20);
BEGIN
l_start := clock_timestamp();
DELETE FROM SHIFT_DATES_COUNT;
FOR I IN C1 LOOP
IF I.TABLE_NAME <> TABLENAME THEN
INSERT INTO SHIFT_DATES_COUNT VALUES (TABLENAME, START_COUNT,
END_COUNT, current_timestamp::timestamp(0));
TABLENAME := I.TABLE_NAME;
END_COUNT := 0;
START_COUNT := 0;
END IF;
IF STRPOS(I.SQL_TEXT, 'END') > 0 THEN
EXECUTE I.SQL_TEXT INTO END_COUNT;
RAISE NOTICE '% ', ('END: ' || I.SQL_TEXT);
ELSE
EXECUTE I.SQL_TEXT INTO START_COUNT;
RAISE NOTICE '% ', ('START: ' || I.SQL_TEXT);
END IF;
END LOOP;
INSERT INTO SHIFT_DATES_COUNT VALUES (TABLENAME, START_COUNT, END_COUNT,
current_timestamp::timestamp(0));
RAISE NOTICE '% ', ('INSERT INTO SHIFT_DATES_COUNT Done...');
l_end := clock_timestamp();
Time_Taken := (l_end-l_start);
RAISE NOTICE '% ', ('FIND_SHIFT_DATES Took: ' || Time_Taken );
END;
$BODY$;
Please let me know how can I use the date_to_find input parameter in the Dynamic SQL in the Cursor in the above Function.
You can use unbound cursor, clause fetch to get data from cursor, and exit when not found to finish, like:
CREATE OR REPLACE FUNCTION example (p_name text) RETURNS void LANGUAGE 'plpgsql' AS $$
DECLARE
C1 refcursor;
res record;
BEGIN
OPEN c1 FOR EXECUTE 'SELECT * FROM pg_database WHERE datname like ''%'||p_name||'%''';
LOOP
FETCH c1 INTO res;
EXIT WHEN not found;
raise notice 'value datname: %',res.datname;
END LOOP;
CLOSE c1;
RETURN;
END; $$;
--in my case
select example ('test')
NOTICE: value datname: test
NOTICE: value datname: test_msmov
NOTICE: value datname: test_resources
NOTICE: value datname: test_load_table
NOTICE: value datname: test_resources2
Total query runtime: 63 msec
1 row retrieved.
You can use EXECUTE clause for open cursor, see the documentation of PostgreSQL
https://www.postgresql.org/docs/10/plpgsql-cursors.html#PLPGSQL-CURSOR-OPENING
Example:
OPEN curs1 FOR EXECUTE format('SELECT * FROM %I WHERE col1 = $1',tabname) USING keyvalue;

Creating TEMP TABLE dynamically in Postgresql and selecting the same table in FOR loop. But getting the error near PIPE symbol

do
$xyz$
declare
y text;
i record;
begin
y := to_char(current_timestamp, 'YYYYMMDDHHMMSS');
raise notice '%',y;
execute 'CREATE TEMP TABLE someNewTable'
||y
||' AS select * from ( VALUES(0::int,-99999::numeric), (1::int, 100::numeric)) as t (key, value)';
for i in (select * from someNewTable||y) loop
raise notice '%',i.key;
end loop;
end;
$xyz$ language 'plpgsql'
ERROR: syntax error at or near "||"
LINE 13: for i in (select * from someNewTable||y) loop
Im unable to understand why the error is at the PIPE symbol. Please help me. I have been trying in Oracle db too, but same error. Am I doing anything wrong here?
The query in for ... loop statement also has to be dynamic, so you should use execute twice.
Use the format() function which is very convenient in conjunction with execute:
do $xyz$
declare
y text;
i record;
begin
y := to_char(current_timestamp, 'YYYYMMDDHHMMSS');
raise notice '%', y;
execute format($ex$
create temp table somenewtable%s
as select * from (
values
(0::int, -99999::numeric),
(1::int, 100::numeric)
) as t (key, value)
$ex$, y);
for i in
execute format($ex$
select * from somenewtable%s
$ex$, y)
loop
raise notice '%',i.key;
end loop;
end;
$xyz$ language 'plpgsql';

Syntax error while creating function in postgresql

I got a syntax error while creating a procedure in postgresql.Here I attached my code.I got a error syntax error near "Continue"
create function patient_form_values() RETURNS void AS
$$ begin
DECLARE columnName varchar(200) ;
DECLARE done boolean default true;
DECLARE CONTINUE handler for not found set done = false;
DECLARE cur1 cursor for select distinct COLUMN_NAME from INFORMATION_SCHEMA.COLUMNS where TABLE_NAME = 'currentdiagnosis';
open cur1;
read_loop : loop
fetch from cur1 into columnName;
if done then leave read_loop;
end if;
set #insertValues := concat('INSERT INTO patient_form_temp(patient_id, form_template_id, creator_id, created_date)
SELECT c.patient_id as patient_id, 41 AS form_template_id, 2 AS creator_id, c.created_date AS created_date
FROM currentdiagnosis c
WHERE c.', columnName,' IS NOT NULL GROUP BY c.patient_id, c.created_date');
select #insertValues;
prepare stmt from #insertValues;
execute stmt;
end loop;
close cur1;
end ;
$$ LANGUAGE plpgsql
You are trying to use a MySQL (or other DB?) function in PostgreSQL. There is no concept of CONTINUE HANDLER in PostgreSQL, so you have to convert the function into PostgreSQL format.
drop FUNCTION if exists migratePartnerAdvertiser();
CREATE OR REPLACE FUNCTION migratePartnerAdvertiser() RETURNS int4 AS '
DECLARE r RECORD;
BEGIN
FOR r IN select distinct COLUMN_NAME from INFORMATION_SCHEMA.COLUMNS where TABLE_NAME = ''currentdiagnosis'' and table_schema=''public'' LOOP
EXECUTE concat(''INSERT INTO patient_form_temp(patient_id, form_template_id, creator_id, created_date) SELECT c.patient_id as patient_id, 41 AS form_template_id, 2 AS creator_id, c.reg_date AS created_date FROM currentdiagnosis c WHERE c.'' , r.column_name , '' IS NOT NULL GROUP BY c.patient_id, c.reg_date'');
END LOOP;
return 1;
END;
' LANGUAGE plpgsql;

Find all occurrences of a string in any column with a specific name in postgresql

I have a Postgresql database with many tables, some of these tables have a column called 'description'. Some of these descriptions contain the word 'dog'. How can I print the tables names for the tables that have the string 'dog' anywhere in the column 'description', case insensitive?
I tried with a script, but it is failing with the error
$$ LANGUAGE plpgsql
ERROR: syntax error at or near "END"
LINE 16: END LOOP;**
This is the script:
CREATE OR REPLACE FUNCTION findAllDogsInDescription()
RETURNS VOID
AS $$
DECLARE
my_row RECORD;
a int;
i boolean;
BEGIN
FOR my_row IN
SELECT table_name from information_schema.columns where column_name = 'description'
LOOP
execute 'select count(*) from ' || my_row.table_name || ' where description ilike ''%dog%'' ' into i;
if (i > 0) THEN
raise 'Found a dog in the description of the table %', my_row.table_name;
END IF
END LOOP;
END;
$$ LANGUAGE plpgsql;
SELECT findAllDogsInDescription();
It's a simple syntax error. You just need a ; after the END IF. And you need to use a (which is an int) instead of i in the execute ... into statement.
CREATE OR REPLACE FUNCTION findAllDogsInDescription()
RETURNS VOID
AS $$
DECLARE
my_row RECORD;
a int;
i boolean;
BEGIN
FOR my_row IN
SELECT table_name from information_schema.columns where column_name = 'description'
LOOP
execute 'select count(*) from ' || my_row.table_name || ' where description ilike ''%dog%'' ' into a;
if (a > 0) THEN
raise 'Found a dog in the description of the table %', my_row.table_name;
END IF;
END LOOP;
END;
$$ LANGUAGE plpgsql;
SELECT findAllDogsInDescription();

For loop with dynamic table name in Postgresql 9.1?

I have a plpgslq function which does some data processing and would like to write a for loop, however my table name is not known at design time. Is there any possible way to achieve this? Here is sample code snippet of what I want to achieve:
-- Function: check_data()
-- DROP FUNCTION check_data();
CREATE OR REPLACE FUNCTION check_data()
RETURNS character varying AS
$BODY$declare
dyn_rec record;
tbl_name record;
begin
-- sample dynamic tables
tbl_name := 'cars';
tbl_name := 'trucks';
tbl_name := 'bicycles';
for dyn_rec in select * from format($$s%$$,tbl_name) loop
raise notice 'item is %',dyn_rec.item_no;
end loop;
return 'Processing Ok';
end;$BODY$
LANGUAGE plpgsql VOLATILE
COST 100;
ALTER FUNCTION check_data()
OWNER TO postgres;
You cannot use a variable as table or column identifier in plpgsql embedded SQL ever. A solution is dynamic SQL - EXECUTE or FOR IN EXECUTE statements:
DO $$
DECLARE
tables text[] = ARRAY['table1','table2'];
table_name text;
rec record;
BEGIN
FOREACH table_name IN ARRAY tables
LOOP
FOR r IN EXECUTE format('SELECT * FROM %I', table_name)
LOOP
RAISE NOTICE '%', rec;
END LOOP;
END LOOP;
END; $$