Create Dynamic Query in SAP using Table Function - hana-sql-script

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

Related

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 ?

Select columns based on condition in Snowflake

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

Teradata Stored Procedure variables

I'm trying to create a stored procedure to create all possible combination of a table with itself. For now, I got this code, but it produces the following error:
Syntax error: expected something between the word 'A' and the integer '2'
Code:
CREATE MULTISET TABLE PRUEBA
(
CAMPO VARCHAR(10)
);
INSERT INTO PRUEBA VALUES('A');
INSERT INTO PRUEBA VALUES('B');
INSERT INTO PRUEBA VALUES('C');
REPLACE PROCEDURE TEST()
BEGIN
DECLARE a VARCHAR(255);
DECLARE b VARCHAR(225);
DECLARE qry VARCHAR(255);
DECLARE i INT;
DECLARE n INT;
SET a = 'SELECT * FROM PRUEBA A1 ';
SET b = ' WHERE ';
SET n = 3;
SET i = 1;
WHILE i < n DO
BEGIN
CASE i
WHEN 1 THEN
SET qry = a;
WHEN 2 THEN
SET a = a || 'CROSS JOIN PRUEBA A' || i ; -- Error in this part.
SET b = b || 'A' || (i-1) || '.CAMPO < A' || i || '.CAMPO';
SET qry = a || b;
ELSE
SET a = a || 'CROSS JOIN PRUEBA A' || i ;
SET b = b || 'AND A' || (i-1) || '.CAMPO < A' || i || '.CAMPO';
SET qry = a || b;
END CASE;
SET i = i + 1;
END;
END WHILE;
EXECUTE IMMEDIATE qry;
END;
CALL TEST();
I'd join the 'i' variable to create multiple alias for all cross tables.
Your i variable is an INTEGER. Try casting it as a VARCHAR() when you do your concatenations:
SET a = a || 'CROSS JOIN PRUEBA A' || CAST(i AS VARCHAR(2)) ; -- Error in this part.
SET b = b || 'A' || CAST((i-1) AS VARCHAR(2)) || '.CAMPO < A' ||
CAST(i AS VARCHAR(2)) || '.CAMPO';
You'll have to do this in the subsequent ELSE block as well.
Use explicit CAST or TRIM to avoid the leading blanks generated by implicit cast from INTEGER to VARCHAR. And you need to use a dynamic cursor to return the result of the SELECT to the caller.
REPLACE PROCEDURE TEST()
DYNAMIC RESULT SETS 1 --Allow returning data to caller
BEGIN
DECLARE a VARCHAR(255);
DECLARE b VARCHAR(225);
DECLARE qry VARCHAR(4096);
DECLARE i INT;
DECLARE n INT;
DECLARE csr1 CURSOR WITH RETURN FOR stmt1; --Declare a dynamic cursor
SET a = 'SELECT * FROM PRUEBA A1 ';
SET b = ' WHERE ';
SET n = 3;
SET i = 1;
WHILE i < n DO
BEGIN
CASE i
WHEN 1 THEN
SET qry = a;
WHEN 2 THEN
SET a = a || 'CROSS JOIN PRUEBA A' || TRIM(i) ;
SET b = b || 'A' || TRIM(i-1) || '.CAMPO < A' || TRIM(i) || '.CAMPO';
SET qry = a || b;
ELSE
SET a = a || 'CROSS JOIN PRUEBA A' || TRIM(i) ;
SET b = b || 'AND A' || TRIM(i-1) || '.CAMPO < A' || TRIM(i) || '.CAMPO';
SET qry = a || b;
END CASE;
SET i = i + 1;
END;
END WHILE;
PREPARE stmt1 FROM qry; --Prepare a dynamic SQL statement for the cursor
OPEN csr1; --Execute the SELECT statement
--Leave a WITH RETURN cursor open to return the result set
END;
if you're using bteq you might have to write the procedure into a file and load it with .compile directive.
once you are loggen in and supposing the file is /tmp/stored_procedure.sql
compile it like this:
.compile file='/tmp/stored_procedure.sql';

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.

Delphi - what am I missing in this query

I am trying to run this query but fail :
procedure TForm4.FormShow(Sender: TObject);
begin
with ClientDataSet1 do
begin
ClientDataSet1.Close;
ClientDataSet1.CommandText :='';
ClientDataSet1.CommandText :='select lokacije.[LOKACIJA_ID],lokacije.[RESORT_ID],'
+ 'lokacije.[HOTEL_ID],lokacije.[NAZIV],'
+ 'uporabniki.[RESORT_ID],uporabniki.[HOTEL_ID],uporabniki.[LOKACIJA_ID],'
+ 'uporabniki.[UPORABNIK],uporabniki.[GESLO],uporabniki.[PRAVICE] from LOKACIJE'
+ 'inner join UPORABNIKI on lokacije.[LOKACIJA_ID]=uporabniki.[LOKACIJA_ID]'
+ 'where lokacije.[NAZIV] = ''' + Form2.AdvOfficeStatusBar1.Panels[3].Text + ''' '
+ 'ORDER BY Uporabniki.[UPORABNIK]';
ClientDataSet1.Open;
end;
end;
I get the error : "Remote error: No such table :LOKACIJEinner"
What am I missing here ???
Database is SQLite. The form that I am opening here is a modal one.The whole app is a datasnap one.This is Client side. Problem is actually this : I have many locations and I only need the data from the name of the location displayed by AdvOfficeStatusBar1.Panels[3].Text.
I think that this is more readable
procedure OpenLokacije(ANaziv: String);
begin
ClientDataSet1.Close;
ClientDataSet1.CommandText := ' select lokacije.[LOKACIJA_ID],'+ // AS Lok_LOKACIJA_ID
' lokacije.[RESORT_ID],'+
' lokacije.[HOTEL_ID],'+
' lokacije.[NAZIV],'+
' uporabniki.[RESORT_ID],'+
' uporabniki.[HOTEL_ID],'+
' uporabniki.[LOKACIJA_ID],'+ // AS Upor_LOKACIJA_ID
' uporabniki.[UPORABNIK],'+
' uporabniki.[GESLO],'+
' uporabniki.[PRAVICE]'+
' from LOKACIJE'+
' inner join UPORABNIKI on lokacije.lokacija_id=uporabniki.lokacija_id '+
' where lokacije.[NAZIV] = :#NAZIV'+
' order by Uporabniki.[UPORABNIK]';
ClientDataSet1.Parameters.ParamByName('#NAZIV').Value:= ANaziv;
ClientDataSet1.Open;
end;
lokacije.lokacija_id and uporabniki.lokacija_id are the same value and field respectively.
use AS:
lokacije.lokacija_id as lok_lokacija_id
uporabniki.lokacija_id as upo_lokacija_id
Also use the schema of the database like
dbo.uporabniki.lokacija_id