【问题标题】:Select where multiple fields are not in subquery (excluding join)选择多个字段不在子查询中的位置(不包括连接)
【发布时间】:2018-10-20 08:32:08
【问题描述】:

我需要提取在存档表中没有历史记录的记录。需要在存档中检查 1 条记录的 2 字段。

从技术上讲,我的要求是左侧连接,右侧为“空”(也称为排除连接),在 abap openSQL 中通常是这样实现的(无论如何,对于我的场景):

Select * from xxxx            //xxxx is a result for a multiple table join
where xxxx~key not in         (select key from archive_table where [conditions] ) 
  and xxxx~foreign_key not in (select key from archive_table where [conditions] )

这 2 个字段还会针对另外 2 个表进行检查,因此这意味着总共有 6 个子查询。

我以前使用过的数据库引擎通常有一些方法来处理此类问题(例如排除连接或外部应用)。

对于这种特殊情况,我将尝试将 ABAP 逻辑与“针对所有条目”一起使用,但 我仍然想知道是否可以使用子查询的结果来检查超过 1 个字段或在多个字段上使用另一种形式的排除连接逻辑,使用 SQL(不涉及应用程序服务器)。

【问题讨论】:

    标签: subquery abap exists opensql


    【解决方案1】:

    如果可以使用子查询的结果来检查超过 超过 1 个字段或在多个字段上使用另一种形式的排除连接逻辑 字段

    不,不可能检查子查询中的两列,正如SAP Help 明确表示的那样:

    子查询中的子句subquery_clauses 必须构成一个标量 子查询。

    标量是这里的关键字,即它应该只返回一列。

    您的子查询可以有多列键,这样的语法是完全合法的:

    SELECT  planetype, seatsmax
      FROM  saplane AS plane
     WHERE seatsmax < @wa-seatsmax AND
           seatsmax >= ALL ( SELECT  seatsocc
                               FROM  sflight
                               WHERE carrid = @wa-carrid AND
                                     connid = @wa-connid     )
    

    但是你说这两个字段应该针对不同的表进行检查

    还对照 两个 更多表格检查这 2 个字段

    所以对你来说不是这样。您唯一的选择似乎是多连接。

    P.S. FOR ALL ENTRIES 不支持否定逻辑,你不能只使用某种NOT IN FOR ALL ENTRIES,它不会那么容易。

    【讨论】:

    • 您的回答为我指明了一个可能的解决方案。我目前正在测试一个在WHERE 子句中使用NOT EXISTS 添加的变体。由于某种原因,我没有立即想到我可以在那里比较尽可能多的字段。但是,我还不确定性能,所以当我有一些结果时,我会尝试更新问题。
    • @Zero,同意。我认为不存在是正确的答案。您可以比较主查询和子查询之间的几个字段。请考虑添加答案,以便我们投票。
    【解决方案2】:

    我已经在我正在制作的程序的生命周期中测试了很多子查询的变体。 NOT EXISTS 在某些情况下,基于 2 个键进行排除的多字段检查(下面的简化示例)有效。 性能可以接受(处理时间约为 5 秒),但在基于 1 个字段排除时,它明显比相同查询慢。

    Select * from xxxx            //xxxx is a result for a multiple table inner joins and 1 left join ( 1-* relation )
    where NOT EXISTS  (
       select key from archive_table 
       where key = xxxx~key OR key = XXXX-foreign_key 
    ) 
    

    编辑: 随着需求的变化(更多过滤)发生了很多变化,所以我想我会更新这个。在我的示例中,我标记为 XXXX 的构造包含一个左连接(其中主表到辅助表的关系是 1-* )并且它看起来相对较快。

    这就是上下文有助于理解问题的地方:

    • 初始要求:拉取所有vendors,3中没有财务记录 表。
    • 附加要求:也排除基于替代 payers1-* 关系)。这就是上面的例子所依据的。
    • 更多要求:也排除基于替代payee*-*payerpayee 之间的关系)。

    多对多连接成倍增加了我标记为XXXX 的构造中的记录数,这反过来又产生了很多不必要的工作。例如:有 3 个payers 和 3 个payees 的单个客户生成了 9 行,总共需要检查 27 个字段(每行 3 个),而实际上只有 7 个唯一值。

    此时,将左连接表从主查询移动到子查询并拆分它们可以显着提高性能。 比任何看起来更聪明的替代品。

    select * from lfa1 inner join lfb1 
           where 
              ( lfa1~lifnr not in ( select lifnr from bsik where bsik~lifnr = lfa1~lifnr )
           and lfa1~lifnr not in ( select wyt3~lifnr from wyt3 inner join t024e on wyt3~ekorg = t024e~ekorg and wyt3~lifnr <> wyt3~lifn2
                                                            inner join bsik  on bsik~lifnr = wyt3~lifn2 where wyt3~lifnr = lfa1~lifnr and t024e~bukrs = lfb1~bukrs  )
           and lfa1~lifnr not in ( select lfza~lifnr from lfza inner join bsik  on bsik~lifnr = lfza~empfk where lfza~lifnr = lfa1~lifnr )
              )
               and [3 more sets of sub queries like the 3 above, just checking different tables].
    

    我的结论

    • 当排除基于单个字段时,not in/not exits 都有效。一种可能比另一种更好,具体取决于您使用的过滤器。
    • 当排除基于 2 个或更多字段并且您在主查询中没有多对多联接时,not exists ( select .. from table where id = a.id or id = b.id or... ) 似乎是最好的。
    • 当您的排除标准在主查询中实现多对多关系时,我建议您寻找一种最佳方式来实现多个子查询(即使每个键表组合都有一个子查询也会比具有 1 个好的子查询的多对多连接性能更好,看起来不错)。

    无论如何,欢迎对此的任何其他见解。

    EDIT2:虽然有点离题,但考虑到我的问题是关于子查询的,我想我会发布一个更新。一年多后,我不得不重新审视我致力于扩展它的解决方案。我了解到正确排除加入工作。我只是在第一次实施它时失败了。

    select header~key 
    from headers left join items on headers~key = items~key
    where items~key is null
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2014-12-07
      • 1970-01-01
      • 1970-01-01
      • 2023-03-20
      • 1970-01-01
      • 2016-08-27
      相关资源
      最近更新 更多