假设我在脚本化计算视图中有一些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)
而不是''''
,但没有使用香蕉:(
答案 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)
- 创建将字符串拆分为多个值的自定义函数
然后可以使用内部/左侧外部联接进行过滤。