HANA - 将字符串变量传递给SQL脚本中的WHERE IN()子句

时间:2017-03-05 18:07:42

标签: hana sql-scripts hana-sql-script

假设我在脚本化计算视图中有一些SQL脚本,它接受单个值输入参数,并在另一个计算视图中为输入参数生成多个输入的字符串。

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)而不是'''',但没有使用香蕉:(

4 个答案:

答案 0 :(得分:1)

SAP注释“2315085 - 脚本计算视图上的多值参数查询失败,语法错误不正确”实际上显示了我第一次尝试时失败的APPLY_FILTER()方法。

它还提供了一个UDF_IN_LIST函数,用于将带有输入参数的项数组的long varchar字符串转换为可用的列表内谓词。

不幸的是,尽管有一些参数可用,但仍无法在sps11 rev 111.03中运行(SAP Note 2457876:将错误转换为警告字符串长度溢出) - (范围3)字符串太长异常

然后ALTER SYSTEM ALTER CONFIGURATION(' indexserver.ini',' System')设置(' sqlscript',' typecheck_procedure_input_param')= '假'与RECONFIGURE;

- 重新编译Calc视图

然后

select * from:var_tempout in OBJECT_ID in(选择I_LIST来自" BWOBJDES"。" CROSS_AREA :: UDF_INLIST_P"(:in_objectids,',')) ;

无效号码例外 - 号码无效

但是从函数中删除脚本可以使它工作......

对于此SPS 11级别,APPLY_FILTER似乎是唯一的解决方法。而且很难说SPS 12的转速是为了拥有它。

networkx.classes.graph.Graph

答案 1 :(得分: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' 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的文档。

答案 2 :(得分:0)

我知道,这是一个很老的话题,但是基于我从Jenova那里读到的内容,我的发现可能对其他人来说很有趣。那就是为什么我要把它们写下来。

我遇到了同样的问题。用户可以在必须优化的calc视图中的输入参数中发送多个条目。不幸的是,我之前遇到过像Jenova和其他人一样的问题。而且,不,恕我直言,这不是关于动态视图执行或动态sql,而是关于在脚本calc视图或表函数中以干净的方式在列表中进行处理(如果它们在输入参数中发送的话)。

根据我的情况,Lars提出的使用APPLY_FILTER的建议不适用,因为我不能在APPLY_FILTER函数本身中使用复杂的语句。我必须在选择中具体化全部数据,可以将结果分配给APPLY_FILTER,然后执行过滤。我想看到的是在实现未出现在过滤器应用程序结果中的数据之后,第一步中未应用过滤器。

因此,我使用hdbtablefunction创建了一个执行参数字符串清除并将其转换为数组的函数,然后返回UNNEST函数的结果。

由于函数的结果是一个表,因此可以将其用作脚本视图或表函数内部的表-在联接,子选择等中。

通过这种方式,我能够按预期的方式快速处理用户输入列表,并减少资源消耗。

FUNCTION "_SYS_BIC"."package1::transparam" (ip_string NVARCHAR(500) ) 
        RETURNS table ( "PARAMETER" nvarchar(100))
        LANGUAGE SQLSCRIPT
        SQL SECURITY INVOKER AS
        v_test varchar(1000);
        IP_DELIMITER VARCHAR(1) := ',';
        v_out VARCHAR(100):='';
        v_count INTEGER:=1;
        v_substr VARCHAR(1000):='';
        v_substr2 VARCHAR(1000):='';
        id INTEGER array;
        val VARCHAR(100) array;
    BEGIN 
    --
     v_substr:=:ip_string; 
     v_substr := REPLACE(:v_substr, '''', '');
     v_substr := REPLACE(:v_substr, ' ', '');
        while(LOCATE (:v_substr, :ip_delimiter) > 0 ) do

            -- find value
            v_out := SUBSTR(v_substr, 0, LOCATE (:v_substr, :ip_delimiter) - 1 );

            -- out to output
            val[v_count]:=v_out;

            -- increment counter
            v_count:=:v_count+1;

            -- new substring for search
            v_substr2 := SUBSTR(:v_substr, LOCATE (:v_substr, :ip_delimiter) + 1, LENGTH(:v_substr));
            v_substr := v_substr2;

        END while;

        IF(LOCATE (:v_substr, :ip_delimiter) = 0 AND LENGTH(:v_substr) > 0) THEN
            -- no delimiter in string
            val[v_count]:=v_substr;

        END IF;

        -- format output as tables
          rst = unnest(:VAL) AS ("PARAMETER");

       RETURN SELECT * FROM :rst;
    END;

可以称为

select * from "package1.transparam"('''BLU'',''BLA''')

两行转盘

PARAMETER
---------
BLU
BLA

答案 3 :(得分:0)

最全面的解释在这里: https://blogs.sap.com/2019/01/17/passing-multi-value-input-parameter-from-calculation-view-to-table-function-in-sap-hana-step-by-step-guide/

  1. 创建将字符串拆分为多个值的自定义函数

然后可以使用内部/左侧外部联接进行过滤。