BigQuery - How to use 'call <stored.procedure>' or output of a procedure in a Select, Insert, With statement - select

Want to do something like this:
Create Function dataset.sp_1(v_table STRING, v_ymd DATE) as (
BEGIN
DECLARE v_select, v_columns, v_dl_table, v_sbx_table, v_filter STRING;
Case v_table
WHEN "tab1" THEN
SET v_dl_table = 'dl_dataset.tab1';
SET v_sbx_table = 'sbx_dataset.tab1';
SET v_columns = 'Timestamp, col1, col2, col3';
SET v_filter = 'AND ColId IS NOT NULL';
End CASE
);
Set v_select = 'SELECT ' || v_columns || ' FROM ' || v_sbx_table|| ' WHERE DATE(Timestamp) = "' || v_ymd || '" ' || v_filter;
EXECUTE IMMEDIATE v_select;
END;
call dataset.sp_1("tab1","2022-01-05"); ---- Works fine.
=-=--= How to make this work=-=-=
Select * from (call dataset.sp_1("tab1","2022-01-05"));
OR
WITH
C as (call dataset.sp_1("tab1","2022-01-05"))
select * from C;
=-=-=-=-=

Related

Postgres function returning a string from a select statement

I am trying to get this function to return a string that comes from the SELECT statement.
CREATE OR REPLACE FUNCTION dbo.fnRepID (pram_ID BIGINT)
RETURNS varchar AS $$
DECLARE
pram varchar := '';
BEGIN
SELECT pram = pram || (Case COALESCE(a.Name, '') WHEN '' THEN '' ELSE b.Name || ' - ' END )
|| (Case COALESCE(b.Name, '' ) WHEN '' THEN '' ELSE b.Name || ' - ' END )
|| f.NAME || ';'
FROM dbo.ClassRelationship a
LEFT JOIN dbo.ClassRelationship b ON a.ParentClassID = b.ClassID and b.Type = 2 and a.Type = 1;
RETURN pram;
END;
$$ LANGUAGE plpgsql;
GRANT EXECUTE ON FUNCTION dbo.fnRepID (BIGINT) TO "postgres";
And this function creation seem to go through just fine, now I want to call this function with 0 as pram_ID but it's saying this basically no matter what I do.
ERROR: query has no destination for result data
HINT: If you want to discard the results of a SELECT, use PERFORM instead.
CONTEXT: PL/pgSQL function dbo.fnrepid(bigint) line 5 at SQL statement
SQL statement "SELECT dbo.fnRepID(0)"
PL/pgSQL function inline_code_block line 2 at PERFORM
SQL state: 42601
I have tried a DO PERFORM block as I have seen similar examples
DO $$ BEGIN PERFORM dbo.fnRepID(0); END $$;but I basically want to get the return value from this function somehow. If there's anything wrong with my procedures please let me know, as I am new to postgres. Thank you.
Edit: Would the following work if I want to append each row of the results into the same var? (can I use select into with the variable on both sides to append to itself?)
CREATE OR REPLACE FUNCTION dbo.fnRepID (pram_ID BIGINT)
RETURNS varchar AS $$
DECLARE
pram varchar := '';
BEGIN
SELECT pram || (Case COALESCE(a.Name, '') WHEN '' THEN '' ELSE b.Name || ' - ' END )
|| (Case COALESCE(b.Name, '' ) WHEN '' THEN '' ELSE b.Name || ' - ' END )
|| f.NAME || ';' INTO pram
FROM dbo.ClassRelationship a
LEFT JOIN dbo.ClassRelationship b ON a.ParentClassID = b.ClassID and b.Type = 2 and a.Type = 1;
RETURN pram;
END;
$$ LANGUAGE plpgsql;
GRANT EXECUTE ON FUNCTION dbo.fnRepID (BIGINT) TO "postgres";
You're doing
SELECT pram = (…) FROM dbo.ClassRelationship a …;
where (…) is an expression that is evaluated and then compared to the current value of pram (which was initialised to an empty string). The query does nothing else, there is no destination for this boolean value (comparison result) it computes, you're getting an error.
You most likely meant to either perform an assignment
pram = SELECT (…) FROM dbo.ClassRelationship a …;
or use an INTO clause:
SELECT (…) INTO pram FROM dbo.ClassRelationship a …;
Notice that you don't even need pl/pgsql to do this. A plain sql function would do as well:
CREATE OR REPLACE FUNCTION dbo.fnRepID(pram_ID BIGINT) RETURNS varchar
LANGUAGE sql
STABLE
RETURN (
SELECT
'' ||
(CASE COALESCE(a.Name, '') WHEN '' THEN '' ELSE b.Name || ' - ' END) ||
(CASE COALESCE(b.Name, '' ) WHEN '' THEN '' ELSE b.Name || ' - ' END) ||
f.NAME ||
';'
FROM dbo.ClassRelationship a
LEFT JOIN dbo.ClassRelationship b ON a.ParentClassID = b.ClassID AND b.Type = 2 AND a.Type = 1
);

Update Null columns to Zero dynamically in Redshift

Here is the code in SAS, It finds the numeric columns with blank and replace with 0's
DATA dummy_table;
SET dummy_table;
ARRAY DUMMY _NUMERIC_;
DO OVER DUMMY;
IF DUMMY=. THEN DUMMY=0;
END;
RUN;
I am trying to replicate this in Redshift, here is what I tried
create or replace procedure sp_replace_null_to_zero(IN tbl_nm varchar) as $$
Begin
Execute 'declare ' ||
'tot_cnt int := (select count(*) from information_schema.columns where table_name = ' || tbl_nm || ');' ||
'init_loop int := 0; ' ||
'cn_nm varchar; '
Begin
While init_loop <= tot_cnt
Loop
Raise info 'init_loop = %', Init_loop;
Raise info 'tot_cnt = %', tot_cnt;
Execute 'Select column_name into cn_nm from information_schema.columns ' ||
'where table_name ='|| tbl_nm || ' and ordinal_position = init_loop ' ||
'and data_type not in (''character varying'',''date'',''text''); '
Raise info 'cn_nm = %', cn_nm;
if cn_nm is not null then
Execute 'Update ' || tbl_nm ||
'Set ' || cn_nm = 0 ||
'Where ' || cn_nm is null or cn_nm =' ';
end if;
init_loop = init_loop + 1;
end loop;
End;
End;
$$ language plpgsql;
Issues I am facing
When I pass the Input parameter here, I am getting 0 count
tot_cnt int := (select count(*) from information_schema.columns where table_name = ' || tbl_nm || ');'
For testing purpose I tried hardcode the table name inside proc, I am getting the error amazon invalid operation: value for domain information_schema.cardinal_number violates check constraint "cardinal_number_domain_check"
Is this even possible in redshift, How can I do this logic or any other workaround.
Need Expertise advise here!!
You can simply run an UPDATE over the table(s) using the NVL(cn_nm,0) function
UPDATE tbl_raw
SET col2 = NVL(col2,0);
However UPDATE is a fairly expensive operation. Consider just using a view over your table that wraps the columns in NVL(cn_nm,0)
CREATE VIEW tbl_clean
AS
SELECT col1
, NVL(col2,0) col2
FROM tbl_raw;

Postgresql: EXECUTE sql_cmd merge with CREATE TEMP TABLE temp_tbl AS SELECT

Soo, here is the thing, I am using in my DB methods 2 approaches:
1.) Is compose and SQL query from various string, depending on what I need to filter out:
sql_cmd := 'SELECT count(*) FROM art_short_term_finished WHERE (entry_time <= ''' || timestamp_up || ''' AND exit_time >= ''' || timestamp_down || ''') AND ' || time_filter || ' AND entry_zone = ' || zone_parameter || ' AND park_uuid = ' || park_id_p || '';
EXECUTE sql_cmd INTO shortterm_counter;
2.) Copy part of the big table, into smaller temp table and work with it:
-- Get the data from FPL into smaller table for processing
DROP TABLE IF EXISTS temp_fpl_filtered;
CREATE TEMP TABLE temp_fpl_filtered AS SELECT car_id FROM flexcore_passing_log fpl WHERE fpl.zone_leaved = '0' AND fpl.status IN (SELECT status_id FROM fpl_ok_statuses) AND fpl.park_uuid = park_id_p AND (fpl.datetime BETWEEN row_i.start_d AND row_i.end_d);
But what If I want to mix those two?
I want to have the SELECT after CREATE TEMP TABLE temp_fpl_filtered AS to have different WHERE clauses depending on input parameters of stored procedure, without having to write the same statement xy times in one stored procedure.
But my approach:
-- art class is shortterm, check shortterm history
IF art_class_p = 1 OR article_p = 0 THEN
-- create temporary table derivated from shortterm history
IF article_p = 0 THEN
article_p_filter := '';
ELSE
article_p_filter := ' AND article_id = ' || article_p;
END IF;
short_cmd := 'SELECT car_id, article_id, entry_time, exit_time FROM art_short_term_finished WHERE zone_leaved = ''0'' AND status IN (SELECT status_id FROM fpl_ok_statuses) ''' || article_p_filter || ''' AND park_uuid = ''' || park_id_p || ''' AND (entry_time <= ''' || timestamp_up || ''' AND exit_time >= ''' || timestamp_down || ''')';
DROP TABLE IF EXISTS temp_short_full;
CREATE TEMP TABLE temp_short_full AS short_cmd;
--EXECUTE sql_cmd INTO shortterm_counter;
END IF;
throws me an exception when I try to inser stored procedure:
psql:report_parking_average.sql:107: ERROR: syntax error at or near "short_cmd"
LINE 50: CREATE TEMP TABLE temp_fpl_filtered AS short_cmd;
^
Also, the another try:
EXECUTE short_cmd INTO TEMP TABLE temp_short_full;
is not working..
You need to include the CREATE TABLE part into the SQL you generate:
short_cmd := 'CREATE TEMP TABLE temp_short_full AS SELECT car_id, article_id, entry_time, exit_time FROM art_short_term_finished WHERE zone_leaved = ''0'' AND status IN (SELECT status_id FROM fpl_ok_statuses) ''' || article_p_filter || ''' AND park_uuid = ''' || park_id_p || ''' AND (entry_time <= ''' || timestamp_up || ''' AND exit_time >= ''' || timestamp_down || ''')';
DROP TABLE IF EXISTS temp_short_full;
execute short_cmd;

Concat text variables in postgresql function

I have this code and I want to concatenate the variables but don't work.
This is my DDL code for the view:
CREATE OR REPLACE function acd.add_credito2()
RETURNS void
SET SCHEMA 'acd'
SET search_path = acd
AS $$
DECLARE
auxsigla text;
auxnome text;
_sql text := 'CREATE OR REPLACE VIEW acd.teste AS SELECT md.matriz_disciplina_id AS id, dcp.nome, mc.curso, mc.versao AS matriz';
_join text := ' FROM matriz_disciplina as md LEFT JOIN disciplina as dcp ON md.disciplina_id = dcp.disciplina_id LEFT JOIN matriz_curricular as mc ON md.matriz_curricular_id = mc.matriz_curricular_id';
BEGIN
select into auxsigla, auxnome from ( select sigla, nome from acd.categoria_credito where categoria_credito_id = 9) as foo;
_join := _join || ' LEFT JOIN (SELECT creditos, matriz_disciplina_id FROM acd.disciplina_credito WHERE categoria_credito_id = ' || x || ') AS ' || "auxsigla" ' ON ' || "auxsigla" || '.matriz_disciplina_id = md.matriz_disciplina_id';
_sql := _sql || ', ' || "auxsigla" || '.' || auxnome || ' AS ' || auxnome;
_sql := _sql || _join;
EXECUTE _sql;
END;
$$ LANGUAGE plpgsql
So, when I execute the function
database-1=# select acd.add_credito2();
This error appears:
ERROR: type "auxsigla" does not exist
LINE 1: ...WHERE categoria_credito_id = ' || x || ') AS ' || "auxsigla"...
^
QUERY: SELECT _join || ' LEFT JOIN (SELECT creditos, matriz_disciplina_id FROM acd.disciplina_credito WHERE categoria_credito_id = ' || x || ') AS ' || "auxsigla" ' ON ' || "auxsigla" || '.matriz_disciplina_id = md.matriz_disciplina_id'
CONTEXT: PL/pgSQL function add_credito2() line 13 at assignment
Can anyone help me? I don't know what to do now.
(I know, this study view don't have a purpose but this is the idea that I want to use in the real view)
The error comes from this construct:
"auxsigla" ' ON '
You forgot a concatenation operator || between these two tokens, and now the SQL parser interprets it as
data_type string_constant
which is a way to specify constants of a certain data type.
Working examples would be DATE '2018-09-20' or INTEGER '-20'.
Your function has numerous other problems, two of which I could spot:
select into auxsigla, auxnome from will always set the variables to NULL because you forgot to specify which columns you want to select.
you do not properly escape single quotes while composing your dynamic query string. What if auxsigla has the value with'quote?
Use format() or quote_literal() and quote_ident() for that.

postgresql insert dynamic query result into table in cursor

i have the following function, that generates dynamic query and at the end i want to insert result of dynamic query into table, but the error i get is `
ERROR: query has no destination for result data
HINT: If you want to discard the results of a SELECT, use PERFORM instead.
CONTEXT: PL/pgSQL function report_get_result(integer) line 46 at SQL statement
SQL statement "SELECT report_get_result(20150131)"
PL/pgSQL function inline_code_block line 2 at PERFORM
********** Error **********'
body of the function is:
CREATE OR REPLACE FUNCTION report_get_result (
datekey integer
) returns setof logic_result_rcd
AS
$body$
DECLARE
LogicID integer;
SheetName text;
Row_ID text;
Column_ID text;
FromTable text;
Operation text;
Amount text;
CriteriaType_1 text;
Function_1 text;
Criteria_1 text;
CriteriaType_2 text;
Function_2 text;
Criteria_2 text;
CriteriaType_3 text;
Function_3 text;
Criteria_3 text;
sql text;
INC Integer;
begin
DROP TABLE IF EXISTS loans;
create temp table loans as
select * from loan.vfact_state_principal where "DateKey" = datekey;
DECLARE cursor_logic REFCURSOR;
BEGIN
OPEN cursor_logic for execute ('SELECT "LogicID" FROM logic_table_rcd');
LOOP
FETCH cursor_logic INTO INC;
if not found then exit;
end if;
BEGIN
SELECT LogicID = "LogicID"
,SheetName = "SheetName"
,Row_ID = "Row_ID"::text
,Column_ID = "Column_ID"::text
,FromTable = "FromTable"
,Operation = "Operation"
,Amount = "Amount"
,CriteriaType_1 = CASE WHEN "CriteriaType_1" <> '' THEN ('WHERE
' || "CriteriaType_1") ELSE '' END
,Function_1 = CASE WHEN "Function_1" is null THEN 'Empty' ELSE
"Function_1" END
,Criteria_1 = CASE WHEN "Criteria_1" is null THEN 'Empty' ELSE
"Criteria_1" END
,CriteriaType_2 = CASE WHEN "CriteriaType_2" <> '' THEN ' AND '
|| "CriteriaType_2" ELSE '' END
,Function_2 = CASE WHEN "Function_2" is null THEN 'Empty' ELSE
"Function_2" END
,Criteria_2 = CASE WHEN "Criteria_2" is null THEN 'Empty' ELSE
"Criteria_2" END
,CriteriaType_3 = CASE WHEN "CriteriaType_3" <> '' THEN ' AND '
|| "CriteriaType_3" ELSE '' END
,Function_3 = CASE WHEN "Function_3" is null THEN 'Empty' ELSE
"Function_3" END
,Criteria_3 = CASE WHEN "Criteria_3" is null THEN 'Empty' ELSE
"Criteria_3" END
FROM public.logic_table_rcd WHERE "LogicID" = INC;
sql:= 'INSERT INTO public.logic_result_rcd SELECT ' || INC::text || ', 1, '
|| EntityID::text || ', ' || DateKey::text || ', ' || 'RCD' || ', ' ||
SheetName::text || ', ' || Row_ID::text || ', ' || Column_ID::text || ', '
|| Operation || '(' || Amount || ')' || ' FROM ' || FromTable
|| CriteriaType_1 || ' ' || Function_1 || ' ' || Criteria_1
|| CriteriaType_2 || ' ' || Function_2 || ' ' || Criteria_2
|| CriteriaType_3 || ' ' || Function_3 || ' ' || Criteria_3;
RETURN QUERY EXECUTE sql;
END;
END LOOP;
CLOSE cursor_logic;
END;
END;
$body$
LANGUAGE plpgsql;
assign value with VAR_NAME := ''; construct, here is an example:
t=# create function f(_i int) returns table (a int) as $$
declare sql text;
begin
sql := format('select %s',_i);
return query execute sql;
end;
$$
language plpgsql
;
CREATE FUNCTION
t=# select * From f(3);
a
---
3
(1 row)