【问题标题】:How do I pass multiple entries through an input parameter mapped from a Table Function in SAP HANA如何通过从 SAP HANA 中的表函数映射的输入参数传递多个条目
【发布时间】:2018-03-28 07:50:58
【问题描述】:

如何通过从 SAP HANA 中的表函数映射的输入参数传递多个条目? 我写了一个带有输入参数的表函数,比如IN_FORMAT_CD。 我已将此参数映射到在我的计算视图中创建的参数。 当我只传递一个值比如 100 时,我能够检索数据。 但是当我传递多个值时,它不会给出任何结果。 有没有相同的解决方法?

我的表格功能:

FUNCTION "HADMIN"."RA.Test.Prathamesh::PH_DEMO" (IN IN_FORMAT_CD NVARCHAR(500)) 
    RETURNS TABLE (NAME NVARCHAR(10), ID NVARCHAR(10), FORMAT_CD NVARCHAR(3))
    LANGUAGE SQLSCRIPT
    SQL SECURITY INVOKER AS
BEGIN
RETURN

SELECT NAME,ID,FORMAT_CD
FROM
HADMIN.PH_DEMO
WHERE FORMAT_CD IN (select :IN_FORMAT_CD as FORMAT_CD from dummy);

END;

【问题讨论】:

    标签: hana


    【解决方案1】:

    你要找的是SAP HANA SQLScriptAPPLY_FILTER函数。

    以下示例显示了您的场景如何编码:

    create function get_vals (IN id_list varchar(400))
    returns table (id bigint, val varchar(40)) 
    as
    begin
    declare myfilter varchar(450) := ' ID in (' || :id_list || ')';
    
     _tmp  = select id, val from some_vals;
     _tmp2 = APPLY_FILTER (:_tmp, :myfilter);
    
     return :_tmp2;
    end;
    
    select * 
    from 
    get_vals ('1, 4, 23, 4, 23, 3');
    

    这种方法会在读取表数据时下推唯一的 ID 列表以用作过滤器。但是,这仍然是dynamic SQL,因此您将失去计划共享等好处,并面临 SQL 注入攻击的风险。阅读更多关于此的信息,例如here

    如果可能,您希望在应用程序代码中处理选择列表。 反过来,这也让您可以选择对临时表使用 IN 列表还是内部连接是适合您情况的最佳方法。

    如果您想将选择列表作为字符串使用,您至少应该确保不使用常见的 SQL 注入攻击,并且“in-list”实际上只包含可能的 ID 值和逗号。

    【讨论】:

    • 你好 Lars,我在我的 ABAP 开发中也使用了 APPLY_FILTER,尤其是在 AMDP 中。但是我想并想了解您对 APPLY_FILTER 的想法是这样的;例如,在您构建 _tmp 表变量时的回复中,我们从 some_vals 表中选择所有行,不是吗?所以我们实际上执行了一个查询,结果是“表扫描”。使用 APPLY_FILTER 从 _tmp 生成 _tmp2 的第二步实际上是在 _tmp 表上执行的,因此我们将无法在 ID 字段上使用索引(我所说的索引是指列表结构具有类似于索引的结构)。你能评论一下吗?
    • 当然。这里的主要误解是关于表变量在 SQLScript 中的工作方式。这些是占位符,仅在需要时才进行评估。简单地分配一个表变量并且从不向它请求数据将导致 SELECT 不会被执行。 SAP HANA 中的优化器预先确定是否将使用特定语句以及将在何处使用结果集。这样您就可以添加诸如APPLY_FILTER 之类的内容,而无需多次执行 SELECT 语句。这也是一种方式,如何将过滤器下推到表访问。
    • 在非常具体的意义上,SQLScript 中的表变量是占位符。在定义应该处理数据的逻辑时,它们代表 SELECT,但它们与实际值不同。
    • 非常感谢。因为我是从第一个表达式创建一个 CDS 视图并对其应用过滤器。由于视图就像您提到的占位符,我认为这表现良好。但是现在我学会了使用APPLY_FILTER的真正方法。非常感谢,
    • 谢谢你,拉斯。那工作得很好。但是,我如何在我的计算视图中使用这个函数,最终用户可以传递他想要的参数?基本上我需要解决这个错误。错误:SAP DBTech JDBC:[257]:sql 语法错误:搜索表错误:“HADMIN”。“RA.Test.Prathamesh::PH_DEMO_AJ”:第 12 行第 1 列(位置 680):[257](范围 3) sql语法错误异常:sql语法错误:SQLScript APPLY_FILTER:过滤变量中的条件不正确:'FORMAT_CD in (\'7,8\')'
    【解决方案2】:

    除非你拆分它们,否则不可能从单个 sql 变量中生成(!)许多项目

    在您的 SQL 子选择查询中,将仅返回 FORMAT_CD 列值与 IN_FORMAT_CD 参数完全相同的行。

    如果此参数表示多个值,则此参数是每个子项的串联字符串表示。所以我们可以把它们分开。 拆分将动态生成一个可用于选择的表格。

    请创建用户自定义的HANA Split functionfnsplit,源代码可以在参考文档中找到

    然后你可以改变你的函数,假设每个值都用“,”与其他值分隔

    ALTER FUNCTION "HADMIN"."RA.Test.Prathamesh::PH_DEMO" (IN IN_FORMAT_CD NVARCHAR(500)) 
        RETURNS TABLE (NAME NVARCHAR(10), ID NVARCHAR(10), FORMAT_CD NVARCHAR(3))
        LANGUAGE SQLSCRIPT
        SQL SECURITY INVOKER AS
    BEGIN
    RETURN
    
    SELECT NAME,ID,FORMAT_CD
    FROM
    HADMIN.PH_DEMO
    WHERE FORMAT_CD IN (
        select str from fnsplit(:IN_FORMAT_CD,',')
    );
    
    END;
    

    【讨论】:

    • 这可行,但不必要的复杂,会减慢查询执行速度。这里更好的选择是APPLY_FILTER
    • @Eralper 通过使用此函数,我如何在表函数中传递值?
    • 我有一个示例函数,我称之为: select * from "A00077387".GetListItems(N'1,2,34,5,68');入参为nvarchar类型字符串变量,内容以逗号分隔
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2014-04-06
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2016-12-27
    • 2020-01-29
    • 2020-12-25
    相关资源
    最近更新 更多