Store select query's output in one array in postgres - sql

My code is:
SELECT column_name
FROM information.SCHEMA.columns
WHERE table_name = 'aean'
It returns column names of table aean.
Now I have declared an array:
DECLARE colnames text[]
How can I store select's output in colnames array.
Is there any need to initialize colnames?

There are two ways. One is to aggregate:
SELECT array_agg(column_name::TEXT)
FROM information.schema.columns
WHERE table_name = 'aean'
The other is to use an array constructor:
SELECT ARRAY(
SELECT column_name
FROM information_schema.columns
WHERE table_name = 'aean'
)
I'm presuming this is for plpgsql. In that case you can assign it like this:
colnames := ARRAY(
SELECT column_name
FROM information_schema.columns
WHERE table_name='aean'
);

I had exactly the same problem. Just one more working modification of the solution given by Denis (the type must be specified):
SELECT ARRAY(
SELECT column_name::text
FROM information_schema.columns
WHERE table_name='aean'
)

Regular:
SELECT post_id FROM posts WHERE(poster_name='John');
output: [
{'post_id': 1},
{'post_id': 2},
{'post_id': 3},
]
Using ARRAY_AGG:
SELECT ARRAY_AGG(post_id) FROM posts WHERE(poster_name='John');
output: [
{[1, 2, 3]}
]

Casting to the datatype "TEXT" will ensure that your queries will run without any problem.
In plpgsql when we assign to a array variable, we need not use the type casting. My requirement was to get a CSV of all the column names of a particular table. I'd used the following code in plpgsql.
Declare col_list varchar[]:=NULL;
cols varchar:=NULL;
Begin
col_list := ARRAY(select t.name from frm_columns t where t.tname='emp_mstr');
cols := array_to_string(col_list,',');
return cols;
End;

CREATE OR REPLACE FUNCTION f_test_array(in _colname text)
returns text as $body$
DECLARE colnames text[];
begin
colnames := ARRAY(
SELECT column_name FROM information_schema.columns WHERE table_name='customer'
);
if exists(select _colname = any(colnames))
then return format('%s it exits.', _colname);
else return format('%s not exits.', _colname);
end if;
end
$body$
LANGUAGE plpgsql;
check if the column exists or not.
Key point: if exists(select _colname = any(colnames))
We can also using string_agg
String_agg usage:
CREATE OR REPLACE FUNCTION f_test_array1(in _colname text)
returns text as $body$
DECLARE colnames text;
begin
colnames := (SELECT string_agg(column_name,',') FROM information_schema.columns WHERE table_name='customer')::text;
if exists(select colnames ilike '%' || quote_literal(_colname) ||'%')
then return format('column %s exits.', _colname);
else return format('column %s does not exits.', _colname);
end if;
end
$body$
LANGUAGE plpgsql;

Related

Use lateral join to loop over all tables from schema

I want to count certain values in all tables of a schema that contain a column that can contain those values.
Was hoping to use a LATERAL join to loop over all tables, but I'm running into issues:
select
fully_qualified_table_name,
cnt
from (
select
'datastore.' || table_name as fully_qualified_table_name
from
information_schema.columns
where
table_schema = 'datastore'
and column_name = 'dss_current_flag'
cross join lateral
select
count(*) as cnt
from
information_schema.fully_qualified_table_name
);
Is this possible?
I'm afraid it is not possible to run dynamic queries using pure SQL. You might wanna check PL/pgSQL instead, e.g.
CREATE OR REPLACE FUNCTION count_records()
RETURNS bigint AS $$
DECLARE
rec record;
res bigint = 0; ct bigint = 0;
BEGIN
FOR rec IN
SELECT table_schema AS sch,table_name AS tb
FROM information_schema.columns
WHERE table_schema = 'datastore' AND column_name = 'dss_current_flag'
LOOP
EXECUTE format($ex$ SELECT count(*) FROM %I.%I $ex$,rec.sch,rec.tb)
INTO ct;
res := res + ct;
END LOOP;
RETURN res;
END $$ LANGUAGE 'plpgsql';
The more flexible approach would be to provide schema and table names as parameters in the function call instead of hard coding it in the function body, such as CREATE FUNCTION count_records(_schema_name text, _table_name text) .., or even the fully qualified table name as a single parameter: CREATE FUNCTION count_records(_qualified_table_name text) ... .
Demo: db<>fiddle
Based on the answer by #jim-jones my final solution was
CREATE TYPE datastore.schema_table_column_counts_type AS (
schema_name text,
table_name text,
column_name text,
value text,
count_p bigint);
CREATE OR REPLACE FUNCTION datastore.count_records_in_schema_where_column_has_value(_schema_name text, _column_name text, _value text)
RETURNS setof datastore.schema_table_column_counts_type language plpgsql AS $$
DECLARE
rec record;
result_record datastore.schema_table_column_counts_type;
BEGIN
FOR rec IN
SELECT
table_schema AS sch,
table_name AS tb,
$2 as cn,
$3 as v
FROM information_schema.columns
WHERE table_schema = $1
AND column_name = $2
LOOP
EXECUTE format($ex$
SELECT
'%1$s' as schema_name,
'%2$s' as table_name,
'%3$s' as column_name,
'%4$s' as value,
count(*)
FROM
%1$s.%2$s
WHERE
%3$s = %4$L
$ex$
, rec.sch, rec.tb, rec.cn, rec.v)
INTO result_record;
return next result_record;
END LOOP;
END $$ ;
SELECT * from datastore.count_records_in_schema_where_column_has_value('datastore', 'dss_current_flag', 'P');

Extract specific Columns from PostgreSQL table and Do an update on its values

I have a PostgreSQL database and I need to do an update over values of specific Columns. The number of columns is so big and I need to do the same operation to different table So better to extract them dynamically.
More specifically I want to extract from the table all the columns whose names ends with "_suffix" and do an update on their values.
I started trying to make a script but I don't know if it is the right road!
SELECT columns.column_name
FROM information_schema.columns
WHERE columns.table_name = 'myInitialTable' AND columns.column_name like '%\_suffix%' AND columns.table_schema = 'public';
I created a view of this query and I used it in the following function :
CREATE OR REPLACE FUNCTION updatetable() RETURNS int4 AS
$BODY$
DECLARE r RECORD;
BEGIN
FOR r IN SELECT * from v_reduced_table LOOP
update myInitialTable
set r.column_name = case
when r.column_name = '' then NULL
when r.column_name = 'value1' or r.column_name = 'value2' then 'xxxxx'
else r.column_name end;
END LOOP;
return 1;
END;
$BODY$
LANGUAGE plpgsql;
SELECT updatetable() as output;
this query do a loop on every column ending with suffix and updates its values. but when I run it I get
ERROR: syntax error at or near "$1"
LINE 1: update myInitialTable set $1 = case when $2 = '' then NULL when ...
Any help is appreciated :)
In your function you need to use dynamic commands.
The funcion format() is often very helpful.
Example data:
create table my_table(col1_suffix text, col2_suffix text, col3_suffix text);
insert into my_table values ('a', 'b', 'c');
Example function:
CREATE OR REPLACE FUNCTION update_my_table() RETURNS void AS
$BODY$
DECLARE r RECORD;
BEGIN
FOR r IN
SELECT columns.column_name
FROM information_schema.columns
WHERE columns.table_name = 'my_table'
AND columns.column_name like '%\_suffix%'
AND columns.table_schema = 'public'
LOOP
EXECUTE(FORMAT($f$
UPDATE my_table
SET %s = CASE
WHEN '%s' = 'col1_suffix' THEN 'col1'
WHEN '%s' = 'col2_suffix' OR '%s' = 'col3_suffix' THEN 'xxxxx'
END;$f$, r.column_name, r.column_name, r.column_name, r.column_name));
END LOOP;
END;
$BODY$
LANGUAGE plpgsql;
Usage:
select update_my_table();
select * from my_table;
col1_suffix | col2_suffix | col3_suffix
-------------+-------------+-------------
col1 | xxxxx | xxxxx
(1 row)

How can I show all tables in data output tab for plpgsql function?

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();

Dynamic Sql: Create array from records using array of column names

I am pulling all of the column_names (cname1) from a crosstab table that I made. There are thousands of these column names so I combined them into an array. I then want to use dynamic sql (or whatever works) to use those column_names to make an array based off of the records of that same crosstab table. I keep getting the error:
ERROR: missing "LOOP" at end of SQL expression
.
CREATE OR REPLACE FUNCTION mffcu.test_ty_hey()
RETURNS setof record
LANGUAGE plpgsql
AS $function$
Declare
cname1 text;
Begin
for cname1 in select array_agg(column_name) as useme
from(
select column_name::text
FROM INFORMATION_SCHEMA.COLUMNS
WHERE TABLE_NAME = 'crosstab_183'
and ordinal_position != 1
) as fin
join mffcu.crosstab_183 a on fin.id = a.id;
loop
sql2 ='select distinct array['|| columnname ||'] from mffcu.crosstab_183';
execute sql2;
end loop;
END;
$function$
I cannot for the life of me figure out why I'm getting this error.
for cname1 in select array_agg(column_name) as useme
from(
select column_name::text
FROM INFORMATION_SCHEMA.COLUMNS
WHERE TABLE_NAME = 'crosstab_183'
and ordinal_position != 1
) as fin
join mffcu.crosstab_183 a on fin.id = a.id; --here should not be semicolon!
loop

Conditionally set a column to its default value in Postgres

I've got a PostgreSQL 8.4 table with an auto-incrementing, but nullable, integer column. I want to update some column values and, if this column is NULL then set it to its default value (which would be an integer auto-generated from a sequence), but I want to return its value in either case. So I want something like this:
UPDATE mytable
SET incident_id = COALESCE(incident_id, DEFAULT), other = 'somethingelse'
WHERE ...
RETURNING incident_id
Unfortunately, this doesn't work - it seems that DEFAULT is special and cannot be part of an expression. What's the best way to do this?
use this:
update mytable set a =
coalesce(incidentid,
(
select column_default::int
from information_schema.columns
where table_schema = 'public'
and table_name = 'mytable' and column_name = 'incidentid')
)
if your incidentid is integer type, put a typecast on column_default
[EDIT]
create or replace function get_default_value(_table_name text,_column_name text)
returns text
as
$$
declare r record;
s text;
begin
s = 'SELECT ' || coalesce(
(select column_default
from information_schema.columns
where table_schema = 'public'
and table_name = _table_name and column_name = _column_name)
, 'NULL') || ' as v';
EXECUTE s into r;
return r.v;
end;
$$
language 'plpgsql';
to use:
update mytable set a =
coalesce(incidentid, get_default_value('mytable','a')::int )