2017-03-05 69 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オプティマイザはうまく機能しますが、特定のアカウント番号の複数のローン番号を入力に変換する方法はありません。この変換をグラフィカルに結合することは、大きなパフォーマンス低下なしには機能しません。代わりに、スクリプトによる計算ビューでグラフィカルなビューをラップして、入力を変換し、パフォーマンスを犠牲にすることなく元のビューに複数のパラメータを照会します。 – Jenova

答えて

0

オクラホマので、あなたがここでやっていることは声明を動的にしようとしている。 IN条件については、あなたがいることを期待しているように見えます。。
あなたはそれがパラメータのセットとして処理されるparamStr満たされている

全くケースはないこと、一度のコメントからあなたの例で行こう:paramStr = ' 'ip1','ip2' '

paramStrがいっぱいになると、何が起こりますあなたのコードには:

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

、代わりにあなたは文字通りIP_DS = ' 'ip1','ip2' 'に一致するレコードを探しているIP_DS = 'ip1' or IP_DS = 'ip2'一致するレコードを探しています。

これを回避する1つの方法は、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()アプローチを実際に示しています。

また、項目の配列を持つ長いvarchar文字列を入力パラメータから使用可能なリスト内述語に変換するためのUDF_IN_LIST関数を提供します。

残念ながら、それがsps11で動作させることができなかったが、いくつかの可能なパラメータ(SAPノート2457876:文字列の長さのオーバーフローのための警告にエラーを変換するため)にもかかわらず、111.03を吹け - (レンジ3)文字列が長すぎ例外では

その後、 ALTER SYSTEM ALTER CONFIGURATION( 'indexserver.ini'、 'System')set( 'sqlscript'、 'typecheck_procedure_input_param')= 'false'でRECONFIGURE;その後、Calcの表示

-recompile

から選択*:OBJECT_IDでは( "BWOBJDES" からI_LISTを選択しvar_tempout。"CROSS_AREA :: UDF_INLIST_P"(:in_objectids、 '、'));

無効な数の例外は - 無効な数

しかし、機能のうち、スクリプトを取るが、それは動作します...このため

は11レベルのAPPLY_FILTERが唯一の回避策であるように思わSPS。そして、それを得るためには、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;