Save the output of a procedure in snowflake in a variable - sql

I have following procedure:
create or replace procedure todays_delivery_amount(targetkey_variable varchar)
returns number
language sql
as
$$
begin
if ((SELECT MONTHLY_DELIVERED_AMOUNT FROM test.process.msv_month_amount where TARGET_KEY = '20') = 0)
then
return ((SELECT monthly_target_amount from test.process.msv_month_amount)/3) ;
else
return ((SELECT monthly_target_amount from test.process.msv_month_amount where TARGET_KEY = '20') - (SELECT MONTHLY_DELIVERED_AMOUNT from test.process.msv_month_amount where TARGET_KEY = '20')) /
(SELECT (SELECT DATEDIFF(DAY,CONCAT(LEFT(current_date(), 8), '01')::date, CONCAT(LEFT(current_date(), 8), (SELECT datediff(dd,current_date(),dateadd(mm,1,current_date()))))::date+1)
- DATEDIFF(WEEK,CONCAT(LEFT(current_date(), 8), '01')::date, CONCAT(LEFT(current_date(), 8), (SELECT datediff(dd,current_date(),dateadd(mm,1,current_date()))))::date+1)) - RIGHT(current_date() -1, 2)::number + CAST(Round((day( current_date() ) +6)/7,0) as VARCHAR)::number);
end if;
end;
$$
;
UNSET todays_amount;
call todays_delivery_amount('10');
Now I want to do two things:
First I would like to save the output of the procedure in the variable todays_amount
So I tried this:
SET todays_amount = call todays_delivery_amount('10');
But this does not work.
And second:
Instead of where TARGET_KEY = '20' i would like to do where TARGET_KEY = targetkey_variable
But this does not work.

It appears that you can't set it directly from the call statement, but you can do this:
UNSET todays_amount;
call todays_delivery_amount('10');
set todays_amount = (select TODAYS_DELIVERY_AMOUNT from table(result_scan(last_query_id())));

Related

Stored Procedure in Snowflake: Use parameter in the where clause

I have following stored procedure in Snowflake:
create or replace procedure test_procedure(parameter varchar)
returns number
language sql
as
$$
begin
if ((SELECT MONTHLY_DELIVERED_AMOUNT FROM test.process.msv_month_amount where TARGET_KEY = parameter) = 0)
then
return null;
else
return (SELECT monthly_target_amount from test.process.msv_month_amount where TARGET_KEY = parameter);
end if;
end;
$$
;
call test_procedure('Key10');
When I try to call the test_procedure it give me following error:
SQL compilation error: error line 1 at position 98 invalid identifier 'parameter'
How do i fix this?
You should prefix the variable name with a colon.
create or replace procedure test_procedure(parameter varchar)
returns number
language sql
as
$$
begin
if ((SELECT MONTHLY_DELIVERED_AMOUNT FROM msv_month_amount where TARGET_KEY = :parameter) = 0)
then
return null;
else
return (SELECT monthly_target_amount from msv_month_amount where TARGET_KEY = :parameter);
end if;
end;
$$
;
call test_procedure('Key10');
Documentation links on the usage are provided below
https://docs.snowflake.com/en/developer-guide/snowflake-scripting/variables.html#using-a-variable-in-a-sql-statement-binding
https://docs.snowflake.com/en/sql-reference/stored-procedures-snowflake-scripting.html#calling-a-stored-procedure-without-using-the-returned-value
User Parameter with single colon (:)
create or replace procedure test_procedure(parameter varchar)
returns number
language sql
as
$$
begin
if ((SELECT MONTHLY_DELIVERED_AMOUNT FROM test.process.msv_month_amount where TARGET_KEY = :parameter) = 0)
then
return null;
else
return (SELECT monthly_target_amount from test.process.msv_month_amount where TARGET_KEY = :parameter);
end if;
end;
$$
;
call test_procedure('Key10');
The code could be simplified to single query and CASE expression:
SELECT CASE WHEN MONTHLY_DELIVERED_AMOUNT = 0 THEN NULL
ELSE monthly_target_amount
END
FROM msv_month_amount
WHERE TARGET_KEY = :parameter

Update command not working inside nested for loop postgres

I have nested for loop as shown below and trying to perform the update statement, but the update command is not working
CREATE or REPLACE FUNCTION public.udf_unit_test_output() RETURNS SETOF text AS
$$
DECLARE
v_expected_proc_name varchar(100);
v_expected_log_severity varchar(25);
v_expected_log_text varchar(8000);
v_expected_occurence int;
v_actual_occurence int;
record_list record;
distinct_unit_test_uuid uuid;
BEGIN
for distinct_unit_test_uuid in
SELECT DISTINCT unit_test_uuid FROM public.unit_test_expected_results
loop
for record_list in select record_id
from public.unit_test_expected_results
WHERE unit_test_uuid = distinct_unit_test_uuid
loop
SELECT proc_name, log_severity, log_text, occurence
FROM public.unit_test_expected_results
WHERE record_id = record_list.record_id
INTO v_expected_proc_name,
v_expected_log_severity,
v_expected_log_text,
v_expected_occurence;
SELECT COUNT(*)
FROM public.unit_test_output uto
WHERE unit_test_uuid = distinct_unit_test_uuid
AND proc_name = v_expected_proc_name
AND log_severity = v_expected_log_severity
AND log_text like v_expected_log_text
INTO v_actual_occurence;
UPDATE public.unit_test_expected_results
SET pass_fail = (CASE WHEN v_expected_occurence = v_actual_occurence
THEN 'PASS' ELSE 'FAIL'
END)
WHERE record_id = record_list.record_id;
RETURN QUERY SELECT is(v_expected_occurence, v_actual_occurence,
'Should contain '||'proc name: ' || v_expected_proc_name || ' severity type: '
|| v_expected_log_severity || ' and log text: ' || v_expected_log_text);
end loop;
end loop;
RETURN;
END;
$$
LANGUAGE plpgsql;
It doesn't update any of the row ?

How to concat variable to other variable in postgresql?

In php connecting variable using . (dot), like $a = "tes", $b="b", if
I connect $a.$b it becomes "tesb". I want this but in postgres
I have tried using dot and + but wrong
my code
CREATE OR REPLACE FUNCTION make_ctx_contoh (rl varchar, dat varchar)
RETURNS numeric AS $total$
declare
date_before date;
dan text;
os_l numeric;
BEGIN
date_before = (DATE_TRUNC('month', NOW())
+ '0 MONTH'::INTERVAL
- '1 DAY'::INTERVAL)::DATE;
if rl = 'nasional' THEN
dan = '';
ELSEIF rl = 'kanwil' THEN
dan = 'AND LOWER(a."KANWIL") = knw';
ELSEIF rl = 'kc' THEN
dan = 'AND LOWER(a."KC") = kac';
END IF;
SELECT
SUM("a"."OUTSTANDING") into os_l
FROM
"public".tbl_nominatif_hasil AS "a"
WHERE
"a"."BUSS_DATE" = date_before AND
"a"."COLLDET" = '1 ' + dan; RETURN os_l;
END; $total$ LANGUAGE plpgsql;
When I run select make_ctx_contoh('kanwil','2'); that shows error like :
ERROR: operator does not exist: unknown + text LINE 6:
"a"."COLLDET" = '1 ' + dan
From what I could understand from your code, you want to add conditions to the where clause based on certain criteria.
So, convert your select query into a AND OR logic.
SELECT
SUM("a"."OUTSTANDING") into os_l
FROM "public".tbl_nominatif_hasil AS "a"
WHERE "a"."BUSS_DATE" = date_before AND
"a"."COLLDET" = 1
AND ( rl = 'nasional' OR
( rl = 'kanwil' AND LOWER(a."KANWIL") = knw) OR
( rl = 'kc' AND LOWER(a."KC") = kac')
)

How to use part of a query inside a variable Oracle Function

I'm trying to use a part of a query into a variable , because I have many ifs to prepare the query , but I have not used something like this.
FUNCTION f_rel_vendas_importacao(vTP_DADOS in varchar2, nCODIGO in number, dDT_COMPRA_INI in DATE, dDT_COMPRA_FIM in DATE, dDT_EFETIVACAO_INI in DATE, dDT_EFETIVACAO_FIM in DATE) RETURN number is
nRetorno number(14,2);
vSTRING VARCHAR2(2000);
begin
IF vTP_DADOS = 'VL_COMISSAO' THEN
vSTRING := 'SUM( DECODE( CPF.CD_MOEDA, 1, CPF.VL_COTACAO_UNIT * CPF.QTDE_COMPRA, ( SELECT Imp_Pack.fu_converte_moeda_ORACLE( CPF.CD_MOEDA, 1, CDT.DT_RECEBIMENTO, CPF.VL_COTACAO_UNIT, 1) * CPF.QTDE_COMPRA FROM dual ) ) )';
END IF;
IF vTP_DADOS = 'QTD_VENDA_SELECTCHEMIE_PERIODO' THEN
vSTRING := 'count(*)';
END IF;
SELECT
vSTRING
INTO
nRetorno
FROM
COMPRA_PROD_FORN CPF,
COMPRA_DATA CDT
WHERE
(CDT.DT_RECEBIMENTO >= dDT_COMPRA_INI AND CDT.DT_RECEBIMENTO <= dDT_COMPRA_FIM) AND
CDT.CD_COMPRA = CPF.CD_COMPRA AND
CDT.CD_TP_DATA = 7 AND
CPF.CD_FORNECEDOR = nCODIGO;
Return nRetorno;
end
f_rel_vendas_importacao;
When you SELECT vString, the result is the content of the variable vString. It doesn't make any attempt to interpret that content as a column or expression. You are best off placing those expressions directly into the query.
IF vTP_DADOS = 'VL_COMISSAO' THEN
SELECT
SUM( DECODE( CPF.CD_MOEDA, 1,
CPF.VL_COTACAO_UNIT * CPF.QTDE_COMPRA,
( SELECT Imp_Pack.fu_converte_moeda_ORACLE( CPF.CD_MOEDA, 1,
CDT.DT_RECEBIMENTO, CPF.VL_COTACAO_UNIT, 1) *
CPF.QTDE_COMPRA
FROM dual ) ) )
INTO
nRetorno
FROM
COMPRA_PROD_FORN CPF,
COMPRA_DATA CDT
WHERE
(CDT.DT_RECEBIMENTO >= dDT_COMPRA_INI AND
CDT.DT_RECEBIMENTO <= dDT_COMPRA_FIM) AND
CDT.CD_COMPRA = CPF.CD_COMPRA AND
CDT.CD_TP_DATA = 7 AND
CPF.CD_FORNECEDOR = nCODIGO;
END IF;
IF vTP_DADOS = 'QTD_VENDA_SELECTCHEMIE_PERIODO' THEN
SELECT count(*)
INTO
nRetorno
FROM
COMPRA_PROD_FORN CPF,
COMPRA_DATA CDT
WHERE
(CDT.DT_RECEBIMENTO >= dDT_COMPRA_INI AND
CDT.DT_RECEBIMENTO <= dDT_COMPRA_FIM) AND
CDT.CD_COMPRA = CPF.CD_COMPRA AND
CDT.CD_TP_DATA = 7 AND
CPF.CD_FORNECEDOR = nCODIGO;
END IF;

How to make a wrapper to return something other than ref cursor

I've got the following PL SQL function that returns a ref cursor but the application i am using does not support ref cursors. How can i make this code return something other than ref cursor
FUNCTION getADedIcWarningsProv(p_hos_id IN work_entity_data.hos_id%TYPE
,p_date IN DATE
)
RETURN eOdatatypes_package.eOrefcur
IS
v_refcur eOdatatypes_package.eOrefcur;
BEGIN
OPEN v_refcur FOR
SELECT IF_type IF_type
,COUNT(*) number_infected
FROM (SELECT DISTINCT bd.PT_id PT_id
,CASE WHEN NVL(O_package.get_O_code_property(pw.warning_code,'Setl'),'N') = 'Y'
THEN cd.description
ELSE 'Other'
END IF_type
FROM PT_ad pad
,BD_details bd
,PT_warnings pw
,codes cd
WHERE bd.current_record = 'Y'
AND bd.BD_location IS NOT NULL
AND bd.BD_status IN (SELECT code
FROM codes
WHERE prog_code IN (1, 1, 2)
AND code_type = 4)
AND bd.AD_no = pad.AD_no
AND pad.hos_id = p_hos_id
AND pw.PT_id = bd.PT_id
AND pw.warning_to IN ('D','Q')
AND p_date BETWEEN pw.applies_start
AND NVL(pw.applies_end,p_date)
AND NVL(O_package.get_O_code_property(pw.warning_code,'INFT'),'Y') = 'N'
AND pw.warning_code = cd.code)
GROUP BY IF_type
ORDER BY IF_type;
RETURN v_refcur;
END getADedIcWarningsProv;
OUTPUT:
IF_TYPE NUMBER_IF
---------------------------------------- ---------------
C 2
M 6
Other 4
3 rows selected
You can use a pipeline function to return a result set one record at a time, but in a way that the SQL engine can understand.
create or replace package WrapperSample is
type TResultRow is record(
if_type codes.cd%type
,number_infected Integer);
type TResultRowList is table of TResultRow;
function GetADedIcWarningsProv
(
p_hos_id in work_entity_data.hos_id%type
,p_date in date
) return TResultRowList
pipelined;
end WrapperSample;
/
create or replace package body WrapperSample is
function GetADedIcWarningsProv
(
p_hos_id in work_entity_data.hos_id%type
,p_date in date
) return TResultRowList
pipelined is
v_refcur eOdatatypes_package.eOrefcur;
currentRow TResultRow;
begin
v_refcur := YourSchema.getADedIcWarningsProv(p_hos_id, p_date);
loop
fetch v_refcur
INTO currentRow;
exit when v_refcur%NotFound;
pipe row(currentRow);
end loop;
close v_refcur;
return;
end;
end WrapperSample;
/
Using this package, you can select your ref cursor:
SELECT if_type
,number_infected
FROM table(WrapperSample.getADedIcWarningsProv(1, 2))