Select columns based on condition in Snowflake - sql

I am trying to find a solution to select columns in Snowflake based on a condition.
For example I only want to select columns which contain the string "id" or only the numeric columns.
Is there any solution for these cases?
Best regards

You can use something as below. Following procedure query the account usage schema and generate a column list and then return a query based on table and column type. This can be extended
create or replace procedure column_list (TBL_NAME STRING, COL_TYPE STRING)
returns string
language javascript
as
$$
var sql_stmt = `select listagg(column_name,',') as col1 from snowflake.account_usage.columns
where table_name = 'FOO' and table_schema = 'PUBLIC' and DATA_TYPE = '` + COL_TYPE + `' and DELETED IS NULL;`;
var create_log_table_stmt = snowflake.createStatement({ sqlText: sql_stmt });
var rs = create_log_table_stmt.execute();
rs.next();
var result = rs.getColumnValue(1);
var final_query = "select " + result + " from " + TBL_NAME;
return final_query;
$$
;
call column_list ('FOO', 'NUMBER');

Related

Create Dynamic Query in SAP using Table Function

I am trying to create Dynamic SQL query using Table Function, so that it can be consumed in ABAP CDS views. For same I have developed an ABAP Class & defined a method "Get_data".
CLASS-METHODS get_data FOR TABLE FUNCTION ztablefunction.
I am expecting below results, I am getting table names from field .
for each Condition record number it should go to its respective table and fetch few fields.
NOTE: Every table will have different structures only Condition
Record no. will always be available, e.g. Table A900 may have Sales
Org field, but A912 might not have Sales Org field
Below image depicts data in Dynamic Tables (Table Fields in Table A)
Below image depicts output I am expecting.
CLASS zcl_fiori_test DEFINITION
PUBLIC
FINAL
CREATE PUBLIC .
PUBLIC SECTION.
INTERFACES if_amdp_marker_hdb.
CLASS-METHODS get_data FOR TABLE FUNCTION ztablefunction.
PROTECTED SECTION.
PRIVATE SECTION.
ENDCLASS.
CLASS zcl_fiori_test IMPLEMENTATION.
METHOD get_data BY DATABASE FUNCTION
FOR HDB
LANGUAGE SQLSCRIPT
OPTIONS READ-ONLY
USING zcds_test dd03l.
declare tabnamearr string;
declare lv_knumharr string;
declare iv_count integer;
declare i integer;
declare lv_query string;
declare lv_kunnr string;
declare lv_vkorg string;
it_cdhdr = select :p_mandt as client,
conditiontype as cond_type,
'' as valid_start,
'' as valid_end,
changedocobjectclass,
changedocobject,
changedocument,
changetransactioncode,
cdhdrcreationdate,
creationdate,
keycombcondrec from zcds_test;
select count( * ) into iv_count from :it_cdhdr;
it_sel = select changedocobject, keycombcondrec from :it_cdhdr;
it_final1 = select
'' as mandt,
'' as kappl,
' ' as kschl,
' ' as vkorg,
'' as vtweg,
' ' as kunnr,
'' as matnr,
'' as kfrst,
'' as datbi,
'' as datab,
'' as kbstat,
' ' as knumh
from dummy;
it_kunnr = select ' ' as knumh, ' ' as kunnr from dummy;
it_vkorg = select ' ' as knumh, ' ' as vkorg from dummy;'''
for i in 1..iv_count do
tabnamearr = :it_sel.keycombcondrec[i] ;
lv_knumharr = :it_sel.changedocobject[i];
IF exists(select *
from dd03l
where tabname = tabnamearr
and fieldname = 'KUNNR'
) then
lv_kunnr = 'select knumh, kunnr from ' || tabnamearr || ' where knumh = ' || lv_knumharr;
EXECUTE immediate lv_kunnr INTO it_kunnr;
END if;
it_cdsview1 = SELECT a.changedocobjectclass,
a.changedocobject,
a.changedocument,
a.changetransactioncode,
a.cdhdrcreationdate,
a.creationdate,
a.keycombcondrec,
cust.kunnr
from zcds_test as a
left join :it_kunnr as cust on a.changedocobject = cust.knumh;
if exists(select *
from dd03l
where tabname = tabnamearr
and fieldname = 'VKORG'
) then
lv_vkorg = ' it_vkorg = select knumh, vkorg from ' || tabnamearr || ' where knumh = ' || lv_knumharr;
EXECUTE immediate lv_vkorg into it_vkorg;
END if;
it_cdsview2 = SELECT a.changedocobjectclass,
a.changedocobject,
a.changedocument,
a.changetransactioncode,
a.cdhdrcreationdate,
a.creationdate,
a.keycombcondrec,
salesorg.vkorg from zcds_Test as a
left join :it_vkorg as salesorg on a.changedocobject = salesorg.knumh;
end for;
return
select <from Final Output table that should be matched with structure of Table Function>
ENDMETHOD.
ENDCLASS.
Above code, I am not able to store data in temporary table as it does not support.
For alternative I have created structure/table using DUMMY table.
But data is getting replaced with new data.
It might be a wrong approach, kindly suggest correct approach to achieve same.
Please let me know, if you need more information

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 ?

Postgres Type of Parameter does not match

I am having an odd problem with Postgres (10.5). I have a function, generate_unique_name which takes in three text values. It works fine; however, calling this function seems to be an issue. When I call the function using:
SELECT generate_unique_name('basic', 'seeds', 'project=' || 2)
It works without issue. I can make the same call several times. Now, when I try the same call, but change the second parameter as below:
SELECT generate_unique_name('basic', 'queue', 'project=' || 2)
Then it seems to fail with the error:
ERROR: type of parameter 9 (text) does not match that when preparing
the plan (character varying) CONTEXT: PL/pgSQL function
generate_unique_name(text,text,text) line 12 at assignment SQL state:
42804
I have tried changing the query to:
SELECT generate_unique_name('basic'::text, 'queue'::text, ('project=' || 2)::text)
But this also fails. If I then kill the connection to postgres DB, and create a new one, and instead start with the second query, it now works, but the first stops functioning.
It seems like postgres decides to stop treating the parameters as text part way through, for no apparent reason. Am I missing something?
EDIT: Code for generate_unique_name
CREATE OR REPLACE FUNCTION public.generate_unique_name(
proposed_name text,
table_name text,
condition text)
RETURNS text
LANGUAGE 'plpgsql'
COST 100
VOLATILE
AS $BODY$
DECLARE
unique_name text;
name_counter integer;
r record;
names_to_check text[];
BEGIN
unique_name = proposed_name;
name_counter = 0;
FOR r IN EXECUTE 'SELECT name FROM ' || table_name || ' WHERE ' || condition LOOP
names_to_check = array_append(names_to_check, r.name::text);
END LOOP;
WHILE unique_name = ANY(names_to_check) LOOP
name_counter = name_counter + 1;
unique_name = proposed_name || ' (' || name_counter || ')';
END LOOP;
RETURN unique_name;
END;
$BODY$;
My guess is there's a value in the name column of the queue table that causes an issue with
names_to_check = array_append(names_to_check, r.name::text)
As Joe mentioned, the issue was with the array_append, which I could not figure out a way to fix. Instead, the generate_unique_names functions was changed to just query the DB continuously.
CREATE OR REPLACE FUNCTION generate_unique_name (proposed_name text, table_name text, condition text) RETURNS text AS
$BODY$
DECLARE
unique_name text;
name_counter integer;
not_unique boolean;
BEGIN
unique_name = proposed_name;
name_counter = 0;
EXECUTE 'SELECT COUNT(*)!=0 FROM ' || table_name || ' WHERE ' || condition || ' AND name = ''' || unique_name || '''' INTO not_unique;
WHILE not_unique LOOP
name_counter = name_counter + 1;
unique_name = proposed_name || ' (' || name_counter || ')';
EXECUTE 'SELECT COUNT(*)!=0 FROM ' || table_name || ' WHERE ' || condition || ' AND name = ''' || unique_name || '''' INTO not_unique;
END LOOP;
RETURN unique_name;
END;
$BODY$ LANGUAGE plpgsql;

Function with Table_name as input and returns a number in Oracle

I have a function that takes table_name as input and returns a number.
The function gets compiled properly but for some reason when I try test the function it throws error - missing keyword.
CREATE OR replace FUNCTION TEST_FUNCTION (name_table IN VARCHAR2) RETURN NUMBER
IS
rday NUMBER;
BEGIN
execute immediate
'select day_i into rday
FROM ' || name_table || '
WHERE day_i = 1 and rownum = 1';
return rday;
END TEST_FUNCTION;
This is how I am testing it Select TEST_FUNCTION ('FDR_REP') from dual;
The syntax for execute immediate is different for an into clause
try
CREATE OR replace FUNCTION TEST_FUNCTION (name_table IN VARCHAR2) RETURN NUMBER
IS
rday NUMBER;
BEGIN
execute immediate 'select day_i
FROM ' || name_table || '
WHERE day_i = 1 and rownum = 1' into rday;
return rday;
END TEST_FUNCTION;

An SQL Query works fine when executed, But the same Query if I'm using in a PL/SQL it shows error

Hi I've the following query which works fine in SQL, I mean it gets executed successfully.
SELECT id_ligne, n_res_id, n_rty_id, NVL (res_va_text, va_res_txt),
NVL (res_va_short_name, va_res_short_name), bl_has_bo, bl_asset,
bl_needs_profile, bl_update_name, bl_popup_mandatory, va_popup_name,
va_itrack_create, va_itrack_delete, va_generic_mail,
n_application_type, bl_mono_profile
FROM t_t_actres_ea4, t_resource_ea4
WHERE res_n_id(+) = n_res_id
AND t_t_actres_ea4.id_ligne NOT IN (
SELECT DISTINCT (t_erralim_ea4.err_n_lineid)
FROM t_erralim_ea4
WHERE 0235303 = t_erralim_ea4.err_n_code_trt
AND err_n_rejecttype = 0)
It gets executed and the desired output is fetched. But when I use the same query for the PL/SQL like below.
L_REQ Varchar2(1000) := 'select ID_LIGNE, N_RES_ID, N_RTY_ID, NVL(RES_VA_TEXT,VA_RES_TXT),NVL(RES_VA_SHORT_NAME,VA_RES_SHORT_NAME), '||
' BL_HAS_BO, BL_ASSET, BL_NEEDS_PROFILE, BL_UPDATE_NAME, BL_POPUP_MANDATORY, VA_POPUP_NAME, ' ||
' VA_ITRACK_CREATE, VA_ITRACK_DELETE, VA_GENERIC_MAIL, N_APPLICATION_TYPE, BL_MONO_PROFILE ' ||
' from T_T_ACTRES_EA4, T_RESOURCE_EA4 ' ||
' where RES_N_ID (+) = N_RES_ID AND T_T_ACTRES_EA4.ID_LIGNE not in ( select distinct(T_ERRALIM_EA4.ERR_N_LINEID) ' ||
' from T_ERRALIM_EA4 ' ||
' where 0235307 = T_ERRALIM_EA4.ERR_N_CODE_TRT AND ERR_N_REJECTTYPE = 0 and T_ERRALIM_EA4.ERR_VA_MSG not like ''Mono-profile%'')';
It gives me the error saying ORA-00936: missing expression
Note: This error is caused when I append this conditon to the sub-query.
and T_ERRALIM_EA4.ERR_VA_MSG not like ''Mono-profile%''
TIA.
Assuming what you provided is what you want, no execute immediate: it cannot compile.
You have
variable declaration := sql statement
You should have
DECLARE
variable declaration
BEGIN
sql statement
END;
The sql statement should have SELECT INTO syntax
SELECT id_ligne, n_res_id, n_rty_id, NVL (res_va_text, va_res_txt),
NVL (res_va_short_name, va_res_short_name), bl_has_bo, bl_asset,
bl_needs_profile, bl_update_name, bl_popup_mandatory, va_popup_name,
va_itrack_create, va_itrack_delete, va_generic_mail,
n_application_type, bl_mono_profile
INTO LREQ
FROM t_t_actres_ea4, t_resource_ea4
WHERE res_n_id(+) = n_res_id
AND t_t_actres_ea4.id_ligne NOT IN (
SELECT DISTINCT (t_erralim_ea4.err_n_lineid)
FROM t_erralim_ea4
WHERE 0235303 = t_erralim_ea4.err_n_code_trt
AND err_n_rejecttype = 0);
#Bob Jarvis is spot on also - you could do
DECLARE
L_REQ Varchar2(1000) := 'select ID_LIGNE, N_RES_ID, N_RTY_ID, NVL(RES_VA_TEXT,VA_RES_TXT),NVL(RES_VA_SHORT_NAME,VA_RES_SHORT_NAME), '||
' BL_HAS_BO, BL_ASSET, BL_NEEDS_PROFILE, BL_UPDATE_NAME, BL_POPUP_MANDATORY, VA_POPUP_NAME, ' ||
' VA_ITRACK_CREATE, VA_ITRACK_DELETE, VA_GENERIC_MAIL, N_APPLICATION_TYPE, BL_MONO_PROFILE ' ||
' from T_T_ACTRES_EA4, T_RESOURCE_EA4 ' ||
' where RES_N_ID (+) = N_RES_ID AND T_T_ACTRES_EA4.ID_LIGNE not in ( select distinct(T_ERRALIM_EA4.ERR_N_LINEID) ' ||
' from T_ERRALIM_EA4 ' ||
' where 0235307 = T_ERRALIM_EA4.ERR_N_CODE_TRT AND ERR_N_REJECTTYPE = 0 and T_ERRALIM_EA4.ERR_VA_MSG not like ''Mono-profile%'')';
BEGIN
EXECUTE IMMEDIATE L_REQ;
END;
This is probably not the best choice, static SQL offers better performance a lot of the time.