2017-03-05 88 views
1

讓我們假設腳本計算視圖中有一些SQL腳本,它接受單個值輸入參數並在另一個計算中爲輸入參數生成多個輸入的字符串視圖。HANA - 將字符串變量傳遞到SQL腳本中的WHERE IN()子句

BEGIN 
declare paramStr clob; 
params = select foo 
     from bar 
     where bar.id = :IP_ID; 

select '''' || string_agg(foo, ''', ''') || '''' 
into paramStr 
from :params; 

var_out = select * 
      from "_SYS_BIC"."somepackage/MULTIPLE_IP_VIEW"(PLACEHOLDER."$$IP_IDS$$" => :paramStr); 
END 

這個按預期工作。但是,如果我改變var_out查詢,並嘗試使用該變量where子句

BEGIN 
... 

var_out = select * 
      from "_SYS_BIC"."somepackage/MULTIPLE_IP_VIEW" 
      where "IP_IDS" in(:paramStr); 
END 

視圖將激活,但我仍沒有得到查詢結果。沒有運行時錯誤,只是一個空的結果集。當我手動將值傳遞給WHERE IN()子句時,一切正常。這似乎是一個基本的問題,但我似乎無法讓它工作。我甚至使用char(39),而不是我的連接表達式'''',但沒有香蕉:(試圖

+0

在這種情況下你會得到什麼錯誤信息?另外:您的視圖名稱中缺少雙引號。你想在這裏做什麼?要麼將您的值輸入到輸入參數或變量中 - 這些不可交換。 –

+0

對不起,我修正了錯字。我沒有得到任何激活或運行時錯誤,當我查詢腳本calc視圖時,我只是沒有得到任何結果,但當用'WHERE'SOME_COLUMN'IN('ip1','ip2 ')'它工作正常。就像我說的,像第一個例子一樣,使用這個IP實現很好。 – Jenova

+0

並不是說它涉及到這個問題,但我有複雜的服務,HANA優化器不會正確推送過濾器。例如,如果我有一項服務來計算單一貸款編號的餘額,那麼HANA優化器的工作效果很好,但無法轉換輸入以傳遞特定帳號的多個貸款編號。如果沒有巨大的性能損失,以圖形方式加入此轉換不起作用。相反,我將圖形視圖封裝在腳本化的calc視圖中,以轉換輸入並使用多個參數查詢原始視圖,而不會犧牲性能。 – Jenova

回答

0

好了,你在這裏做的是試圖使語句動態。 用於上述條件,你似乎希望一旦您填寫paramStr這將作爲一組參數來處理

,該案件不是在所有
讓你的榜樣去從註釋:。paramStr = ' 'ip1','ip2' '

會發生什麼,當paramStr得到填補到你的代碼是這樣的:

var_out = select * 
      from "_SYS_BIC"."somepackage/MULTIPLE_IP_VIEW" 
      where "IP_IDS" in(' ''ip1'',''ip2'' '); 

因此,而不是尋找符合IP_DS = 'ip1' or IP_DS = 'ip2'的記錄,你是從字面上尋找符合IP_DS = ' 'ip1','ip2' '的記錄。

解決此問題的一種方法是使用APPLY_FILTER()函數。

var_out = select * 
      from "_SYS_BIC"."somepackage/MULTIPLE_IP_VIEW"; 

filterStr = ' "IP_IDS" in (''ip1'',''ip2'') '; 

var_out_filt = APPLY_FILTER(:var_out, :filterStr) ; 

前段時間我寫過:"On multiple mistakes with IN conditions"。 另外,看看APPLY_FILTER的文檔。

+0

工作正常,但現在我在第一次執行時出現了糟糕的性能,當我手動執行相同的查詢時,它閃電般快速... – Jenova

0

SAP註釋「2315085 - 在腳本計算視圖上使用多值參數查詢失敗,語法錯誤不正確」實際上展示了我第一次嘗試時失敗的APPLY_FILTER()方法。

它還提供了一個UDF_IN_LIST函數,用於將具有項目數組的長varchar字符串從輸入參數轉換爲可用的列表中謂詞。

不幸的是,不能讓它在SPS11工作修訂版111.03儘管有一些可用的參數(SAP註釋2457876:出錯轉換成字符串長度溢出警告) - (距離3)字符串太長例外

然後ALTER SYSTEM ALTER CONFIGURATION('indexserver.ini','System')set('sqlscript','typecheck_procedure_input_param')='false'WITH RECONFIGURE;

-recompile Calc的查看

然後

SELECT * FROM:var_tempout其中OBJECT_ID中(選擇 「BWOBJDES」 I_LIST。「CROSS_AREA :: UDF_INLIST_P」(:in_objectids, ''));

無效數字異常 - 無效號碼

但考慮腳本出來的功能,使得它的工作...

對於這一SPS 11級APPLY_FILTER似乎是唯一的解決方法。而要真正實現它,真的很難說什麼是SPS 12的改革。

FUNCTION "BWOBJDES"."CROSS_AREA::UDF_INLIST_P"(str_input nvarchar(5000), 
delimiter nvarchar(10)) 
RETURNS table (I_LIST INTEGER) LANGUAGE SQLSCRIPT SQL SECURITY INVOKER AS 
/********* Begin Function Script ************/ 
BEGIN 
DECLARE cnt int; 
DECLARE temp_input nvarchar(128); 
DECLARE slice NVARCHAR(10) ARRAY; 

temp_input := :str_input; 
cnt := 1; 
WHILE length(temp_input) > 0 DO 
    if instr(temp_input, delimiter) > 0 then 
     slice[:cnt] := substr_before(temp_input,delimiter); 
     temp_input := substr_after(temp_input,delimiter); 
     cnt := :cnt + 1; 
    else 
     slice[:cnt] := temp_input; 
     break; 
    end if; 
END WHILE; 
tab2 = UNNEST(:slice) AS (I_LIST); 
return select I_LIST from :tab2; 
END; 

CREATE PROCEDURE "MY_SCRIPTED_CV/proc"(IN numbers NVARCHAR(5000), OUT 
var_out 
MY_TABLE_TYPE) language sqlscript sql security definer reads sql data with 
result view 
"MY_SCRIPTED_CV" as 
/********* Begin Procedure Script ************/ 
BEGIN 
    -- not working 
    --var_out = select * from MY_TABLE where NUMBER in (select I_LIST from 
    --UDF_INLIST_P(:numbers,',')); 

    -- working 
    DECLARE cnt int; 
    DECLARE temp_input nvarchar(128); 
    DECLARE slice NVARCHAR(13) ARRAY; 
    DECLARE delimiter VARCHAR := ','; 

    temp_input := replace(:numbers, char(39), ''); 
    cnt := 1; 
    WHILE length(temp_input) > 0 DO 
    if instr(temp_input, delimiter) > 0 then 
     slice[:cnt] := substr_before(temp_input,delimiter); 
     temp_input := substr_after(temp_input,delimiter); 
     cnt := :cnt + 1; 
    else 
     slice[:cnt] := temp_input; 
     break; 
    end if; 
    END WHILE; 
l_numbers = UNNEST(:slice) AS (NUMBER); 

var_out= 
SELECT * 
FROM MAIN AS MA 
INNER JOIN l_numbers as LN 
ON MAIN.NUMBER = LN.NUMBER 

END;