简化重复性SQL

2020-08-18 17:36发布

点击此处---> 群内免费提供SAP练习系统(在群公告中)加入QQ群:457200227(SAP S4 HANA技术交流) 群内免费提供SAP练习系统(在群公告中)在AMDP中,我将BW中的数据从...

         点击此处--->   EasySAP.com群内免费提供SAP练习系统(在群公告中)

加入QQ群:457200227(SAP S4 HANA技术交流) 群内免费提供SAP练习系统(在群公告中)


在AMDP中,我将BW中的数据从关键指标模型ADSO转换为帐户模型ADSO。 我有这种形式的SQL:

选择field1,field2,field3,
        IFNULL((从LOOKUP中选择映射,其中field1 =:intab.field1
                                           AND帐户='VV000'),
                 " VV000")作为帐户,
        vv000_value作为值
      来自:intab
      其中vv000_value> 0
 联盟
 选择field1,field2,field3,
        IFNULL((从LOOKUP中选择映射,其中field1 =:intab.field1
                                            AND帐户='VV001'),
                 " VV001")作为帐户,
        vv001_value作为值
     来自:intab
     其中vv001_value> 0
 联盟
 ... 

每个VVnnn是一个帐户。 对于某些帐户,需要将它们在帐户模型中映射为其他名称。 但是默认情况下,使用相同的帐户名。

对于每个帐户,我都有一个单独的UNION。 来源中可能有20到30个关键指标。 无论如何,有没有消除此代码重复并简化SQL的方法?

2条回答
shere_lin
2020-08-18 17:51 .采纳回答

这是所谓的"枢轴"查询的经典示例。
尽管SAP HANA流程图/智能数据质量为此提供了建模工具(而且您很可能具有看看)。HANASQL并未为此操作提供" PIVOT"关键字(它不是标准SQL的一部分)。

这意味着,作为开发人员,您在这里几乎没有选择并且编写重复的代码。

避免这种情况的一种选择是元编程。 编写一个为您生成代码的程序。 如果您发现自己经常进行这种块复制编码,那可能是值得的。

对于一次有限数量的关键指标(任何低于200的数字)来说,这可能不会奏效。

因此,我的目标是尽可能简化这一过程。

要重写该构造,我将UNION更改为UNION ALL,然后将内联选择转换为外部联接,如下所示:

选择/* ACT 1 */
         k.f1,k.f2,k.f3
         ,IFNULL(l.mapped,'ACT1')作为account_name
         ,ACT1作为account_value
     来自kftab k
     左外部联接查找l
     开(k.f1,'ACT1')=(l.f1,l.act)
     哪里
         k.ACT1!= 0.0
 全联盟
     选择/* ACT 2 */
            k.f1,k.f2,k.f3
         ,IFNULL(l.mapped,'ACT2')作为account_name
         ,ACT2作为account_value
     来自kftab k
     左外部联接查找l
     开(k.f1,'ACT2')=(l.f1,l.act)
     哪里
         k.ACT2!= 0.0

 全部合并
 ... 

这使SELECT列表更容易阅读(至少对我而言),并将JOIN条件放在我期望的位置。
最初,我认为这也会导致更好的性能,因为内联选择似乎 对每个记录执行一次,而对整个选定数据集执行一次外部联接。 但是,情况并非如此,因为HANA优化器(在HANA 2 SP 03上进行了测试)会自动重写查询,因此这两种方法都导致相同的执行计划(外部联接)。

使用UNION ALL比UNION便宜一点,因为最终结果集仍然不需要额外的DISTINCT操作(即,根据定义,此处的UNION部分并不重叠)。

现在,这看起来仍然很丑陋,主要部分实际上是IFNULL和JOIN构造。

这可以隐藏在标量用户定义函数(sUDF)中,类似于:

创建函数remap_act_name(IN F1 varchar(20),IN ACT nvarchar(20))
 返回确定性的act_name varchar(20)
 如
 开始
     选择合并(max(mapped),:ACT)到act_name
     来自(
           选择映射
           从查找
           哪里
                   f1 =:F1
              和行动=:ACT
          全部合并
          选择to_varchar(null)作为映射
          来自假人);
 结束;
 

此SELECT看起来有点复杂,但是SELECT FROM DUMMY部分仅用于确保至少返回一条记录(否则,不匹配会导致" 未找到数据"错误)

有了此功能,我们就可以摆脱所有联接,查询看起来像这样:

选择/* ACT 1 */
         k.f1,k.f2,k.f3
         ,remap_act_name(k.f1,'ACT1')作为account_name
         ,ACT1作为account_value
     来自kftab k
     哪里
         k.ACT1!= 0.0
 全部合并
     选择/* ACT 2 */
         k.f1,k.f2,k.f3
         ,remap_act_name(k.f1,'ACT2')作为account_name
         ,ACT2作为account_value
     来自kftab k
    
     哪里
         k.ACT2!= 0.0
 合并所有
...

这大大提高了语句的可读性,并将查找逻辑放在一个地方。 还不错。

当然,没有什么是免费的,因此这种方法的性能特征比纯SQL的要差。

提供一些见解:尽管纯(且费解)的SQL需要40ms和1.6 MB来完成我的最小测试数据集,但UDF方法大约花费了两倍的时间和200 MB的RAM。
这些数字实际上没有任何意义,因为它们完全取决于要处理的数据量,但应说明使用UDF时会产生影响。
如果获得的代码可维护性值得,那么此"成本"需要逐案判断。 如果没有强烈的动机来节省计算资源,我可能会采用UDF方法。

一周热门 更多>