PostgreSQL: column names into array PL/pgSQL - arrays

create or replace function extr( tabname text ) returns text[] as
$$
declare cols text[];
begin
execute 'array(select column_name::text from information_schema.columns where table_name = '||quote_literal(tabname)||');' into cols;
return cols;
end;
$$
language 'plpgsql';
select extr('test');
One supplies a table name and wants back its column-names as an array. The above code gives 'syntax error at or near "array"'. How to fix this?

The query should start with select, not array and it doesn't have to be dynamic SQL.
Try this modified version:
create or replace function extr( tabname text ) returns text[] as
$$
declare cols text[];
begin
select array(select column_name::text from information_schema.columns
where table_name = tabname) into cols;
return cols;
end;
$$
language 'plpgsql';

Related

Snowflake SQL Procedure Parameters

Apologies but I can't seem to find documentation on this.
I am passing in two strings converting them to date to find the number of rows.
Its a silly question but how do I pass in parameters to a SQL query for cursor
CREATE OR REPLACE PROCEDURE LOAD_DATA("START_DATE" VARCHAR(12), "END_DATE" VARCHAR(12))
RETURNS FLOAT
LANGUAGE SQL
EXECUTE AS OWNER
AS '
declare
row_count float;
c1 cursor for select etl_year,etl_month,etl_day_of_year,1 as rowx
from dim_etldate
where etl_date >= to_date(start_date,''dd-mm-yyyy'')
and etl_date <= to_date(end_date,''dd-mm-yyyy'');
begin
row_count := 0.0;
open c1;
for rec in c1 do
row_count := row_count + 1;
end for;
close c1;
return row_count;
end;
';
Error is invalid identifier 'START_DATE'
If you use an argument in the SQL statement you need to put a colon : in front of it, like in this example (observe the id argument):
CREATE OR REPLACE PROCEDURE find_invoice_by_id(id VARCHAR)
RETURNS TABLE (id INTEGER, price NUMBER(12,2))
LANGUAGE SQL
AS
DECLARE
res RESULTSET DEFAULT (SELECT * FROM invoices WHERE id = :id);
BEGIN
RETURN TABLE(res);
END;
More information here.

issue when executing the pgsql complaining about loop

create or replace function f() RETURNS void AS
declare
tableArray text[] := '{"ADDRESS","CONSISTENCY_CHECK","DEPARTMENT_SUPERVISION"}';
tableName CHARACTER VARYING;
value INTEGER ;
BEGIN
FOREACH tableName IN ARRAY tableArray
LOOP
select user_id from tableName where user_id=2631;
if found then
update tableName set user_id=2651 where user_id=2631;
delete from tableName where user_id=2631;
END loop;
end;
here is the error that I get when trying to execute the pgplsql: ERROR syntax error at or near "loop"
There are more issues:
the body of function should be string - you can use apostrophes or more usual and practical $$ custom string separators.
the result of SELECT should not be lost. The clause INTO is missing.
table name should not be a variable - variable cannot be used as table name. In this case you need dynamic SQL - EXECUTE statement.
camel notation for variable names should not be used for SQL language, that is case insensitive
CREATE OR REPLACE FUNCTION f()
RETURNS void AS $$
DECLARE
table_array text[] := '{"ADDRESS","CONSISTENCY_CHECK","DEPARTMENT_SUPERVISION"}';
table_name text;
value integer ;
rc integer
BEGIN
FOREACH table_name IN ARRAY table_array
LOOP
EXECUTE format('SELECT * FROM %I WHERE user_id = $1', table_name) USING 2631;
-- variable FOUND cannot be used for dynamic SQL
GET DIAGNOSTICS rc = ROW_COUNT;
IF rc > 0 THEN
EXECUTE format('UPDATE %I SET user_id = $1 WHERE user_id = $2', table_name) USING 2651, 2631;
EXECUTE format('DELETE %I WHERE user_id = $1', table_name) USING 2631;
END IF;
END LOOP;
END;
$$ LANGUAGE plpgsql;

How to use a function to get from tablename in postgresql?

thanks for help.
Sorry for bad english.
I created a function to return a tablename, for use in my select statement, here the script of function:
CREATE OR REPLACE FUNCTION getfromtable(objecttype varchar, destinationtable varchar, firstdate date, OUT tablename varchar)
AS $BODY$
declare
objectType ALIAS FOR $1;
destinationTable ALIAS FOR $2;
firstDate ALIAS FOR $3;
--tableResult varchar;
BEGIN
IF UPPER(objectType) = 'VIEW' THEN
select destinationTable || to_char(cast(firstDate as date),'yy') into tablename;
END IF;
IF UPPER(objectType) = 'TABLE' THEN
select destinationTable || to_char(cast(firstDate as date),'mmyy') into tablename;
END IF;
END;
$BODY$
LANGUAGE plpgsql
I need use this function, because i have table names with MMYY or views with YY in name ... the function works correctly, but, i need to use it in select, for example:
select * from getfromtable('TABLE','tab_venda_',current_date)
But, here is my problem, if i execute the script, the postgres return the table name, but not execute a select from a table ... i need execute a select in a table, not return the function...
How I wish it were
select * from tab_venda_0319
Whats i'm doing wrong?
You are not really doing something wrong, but functions just do not work that way. What the function returns is not a table name, but a value (parsing and query plan buildung are already done at that point).
Perhaps partitioning might help you?
Instead of returning the table name you can return the query result. See modified function.
CREATE OR REPLACE FUNCTION getfromtable(objecttype varchar, destinationtable varchar, firstdate date)
RETURNS SETOF RECORD
AS $BODY$
declare
objectType ALIAS FOR $1;
destinationTable ALIAS FOR $2;
firstDate ALIAS FOR $3;
tablename varchar;
BEGIN
IF UPPER(objectType) = 'VIEW' THEN
select destinationTable || to_char(cast(firstDate as date),'yy') into tablename;
END IF;
IF UPPER(objectType) = 'TABLE' THEN
select destinationTable || to_char(cast(firstDate as date),'mmyy') into tablename;
END IF;
RETURN QUERY EXECUTE 'SELECT * FROM '||tablename;
END;
$BODY$
LANGUAGE plpgsql;
While selecting you need to provide the column list for this to work as below
SELECT * FROM getfromtable('TABLE','tab_venda_',current_date) AS tab(column1_name column1_type, ...);

Merging and returning arrays

I've two functions,
CREATE OR REPLACE FUNCTION function_a(input varchar)
RETURNS setof integer AS $$
BEGIN
RETURN QUERY
SELECT somecolumn FROM some_things WHERE a_column = input;
END;
$$ LANGUAGE PLpgSQL;
CREATE OR REPLACE FUNCTION function_b(inputs varchar[])
RETURNS setof integer AS $$
DECLARE
input varchar;
result integer[];
BEGIN
FOREACH input IN ARRAY inputs LOOP
result := result || ARRAY[function_a(input)];
END LOOP;
END;
$$ LANGUAGE PLpgSQL;
I am running it like,
SELECT function_b(ARRAY['a', 'b']);
The error,
ERROR: query "SELECT result || ARRAY[function_a(input)]" returned more than one row
CONTEXT: PL/pgSQL function function_b(character varying[]) line 7 at assignment
All I want to do is to run a function over an array. I've always used scripting languages like Ruby to do this kind of stuff instead of using SQL, but I'm trying to learn SQL as it is much faster to get results on the db console itself. I wish it wasn't so frustrating.
First, in SQL we mainly write queries. You can do the same with a simple query:
select somecolumn
from some_things
where a_column = any(array['a', 'b']);
If you need a function, it may be an SQL one:
create or replace function sql_function(inputs text[])
returns setof integer language sql as $$
select somecolumn
from some_things
where a_column = any(inputs);
$$;
SQL functions are simpler and usually faster than plpgsql ones.
Back to your function_b() - the array constructor should look like this:
ARRAY(SELECT function_a(input))
Note also that the function does not return anything. Because you aggregate results in an array, you should unnest it to return rows:
CREATE OR REPLACE FUNCTION function_b(inputs varchar[])
RETURNS setof integer AS $$
DECLARE
input varchar;
result integer[];
BEGIN
FOREACH input IN ARRAY inputs LOOP
result := result || ARRAY(SELECT function_a(input));
END LOOP;
RETURN QUERY SELECT unnest(result);
END;
$$ LANGUAGE PLpgSQL;
You don't need the first function at all. I believe you want to return a set of integers from the table for the given input. A function like this is all you need.
CREATE OR REPLACE FUNCTION function_b(inputs varchar[])
RETURNS setof integer AS $$
BEGIN
RETURN QUERY SELECT somecolumn
FROM some_things WHERE a_column = ANY ( inputs );
END;
$$ LANGUAGE PLpgSQL;
Demo

Postgres STRING_TO_ARRAY alternative? Like STRING_TO_RECORD?

I need to convert a comma separated text into a set of records. I created this function
but I am not convinced that the best way:
CREATE OR REPLACE FUNCTION F_StringListToRecord(pStringList TEXT, pDelimiter VARCHAR(10)) RETURNS SETOF RECORD AS $$
DECLARE
vIndex INT;
arrSize INT;
arrValue TEXT[];
BEGIN
arrValue := STRING_TO_ARRAY(pStringList, pDelimiter);
arrSize := ARRAY_UPPER(arrValue, 1);
FOR vIndex IN 1..arrSize LOOP
RETURN QUERY SELECT arrValue[vIndex];
END LOOP;
END $$
LANGUAGE plpgsql;
Is there any other function similar to STRING_TO_ARRAY (perhaps STRING_TO_RECORD)?
In 8.4 you can use:
select * from unnest(string_to_array(my_string_here,delimiter)) as v(x);

Resources