【问题标题】:Check if any element in list A exists in list B检查列表 A 中的任何元素是否存在于列表 B 中
【发布时间】:2019-10-17 19:19:19
【问题描述】:

我在工作中学习 Oracle SQL,并且正在寻找一些(理想情况下紧凑且高效的)条件表达式,如果列表 A 中的任何项目出现在列表 B 中,则该条件表达式的计算结果为真。

我有一个表IVS,其中包含一列值CODES,还有一个表POP,其中包含一组列(CDE_VAL_1CDE_VAL_26)。对于POP 中的任何行/记录,每个CDE_VAL_* 字段可能包含来自IVS.CODES 列的值,或者包含NULL。假设我有IVS 的一个子集(称为IVS_sub),那么我正在寻找一种方法来选择POP 的子集,这样每个选定的记录在@987654337 的任何一个中都有一些来自IVS_sub.CODES 的代码@字段。

我的代码“有效”但运行速度太慢,以至于我无法在一天内测试我的代码超过一两次。显然这太慢了,我需要能够以合理的周转率测试和重写/修复代码。

这是我当前的(慢速)方法作为一个最小示例:

SELECT DISTINCT * FROM POP 
INNER JOIN IVS 
    ON IVS.CODES IN (CDE_VAL_1, /*... pretend i listed them all here*/, CDE_VAL_26)

请注意,我正在运行的实际查询要复杂得多,还有其他几个连接、过滤等(也就是说,我肯定我的瓶颈是这个问题,删除IVS 连接将查询从 ~2.5 小时缩短到 ~10 分钟)。

我也试过了:

SELECT DISTINCT * FROM POP 
INNER JOIN IVS ON (CDE_VAL_1 IN IVS.CODES
                   OR CDE_VAL_2 IN IVS.CODES
                   /* ... */
                   OR CDE_VAL_26 IN IVS.CODES)

但是,这既杂乱又丑陋,更重要的是,它使代码更难遵循。它似乎也没有运行得特别快,至少对于我运行的小型测试查询。

最好我想以类似的方式结束

SELECT * FROM POP
/* other joins and stuff */
INNER JOIN IVS ON ANY_OF(CDE_VAL_1, ... ) IN IVS.CODES
WHERE /*where conditions*/

或类似的,ANY_OF(...) IN ... 只是代表任何解决方案。理想情况下,该解决方案将是一个相对紧凑的 sn-p,一目了然。

从概念上讲,这只是“如果这两个列表的交集不为空”,但到目前为止我还没有看到类似的东西。

(注意:我们没有使用 PL/SQL,只是纯粹的 Oracle SQL 查询,不过如果有需要 PL/SQL 的解决方案,我很想听听它们,如果只是用它们作为弹药来说服我老板给我们一些培训什么的。)

【问题讨论】:

  • 你检查过这个问题吗? stackoverflow.com/questions/39001651/…
  • 仅供参考,但不推荐。在包含多列代码的 POP 表中,选择它作为长文本字符串,每个 CDE_VAL_X 列之间有竖线分隔符。然后加入另一个表,在该表中选择要查找的每个代码作为“|code|”并加入文本字符串包含。它在字符串搜索的权衡下避免了 SQL 查询中的 if then else。成本/收益取决于行数、要匹配的代码数量等。
  • @RodrigoDíazLupanow 我确实看到了那个。也许我不理解那里提出的解决方案,但我认为它并不完全适用。问题在于,他们的 ListA 版本似乎是一种可以从中选择/加入的类型,在我的情况下, ListA 只是一个包含任何给定行的字段的列表文字。每行都有自己的代码,构成该行的“ListA”。
  • @stak 这正是我第一次发现这是一个问题时的想法,但是对于尽可能多的代码、列和行,它最终比我的慢速方式慢得多不要在上面提到它。
  • 您能否在edit 您的问题中包含带有 DDL 语句的 minimal reproducible example 以获取我们表的最小示例(您不需要所有 26 列)和 DML 语句以获取一些示例数据,然后提供该数据的预期输出(以及从输入到输出的必要逻辑细节)。它可能有助于我们了解您想要实现的目标,因为代码本身对于您期望它如何转换数据相当混乱。

标签: sql oracle


【解决方案1】:

您可以使用 unpivot 解决您的问题。举个例子:

  with ivs as (
    select '1' codes from  dual
     union all
    select '6' codes from  dual  ),
    pop as    (
        select  1 id, '1' CDE_VAL_1, '2' CDE_VAL_2 ,'3' CDE_VAL_3 , '4' CDE_VAL_4,'5' CDE_VAL_5 from  dual
    union all
         select 2 id, '7' CDE_VAL_1, '8' CDE_VAL_2 , '9' CDE_VAL_3 , '10' CDE_VAL_4, '6' CDE_VAL_5 from  dual
    ),
    pop_unpivot as (
    select * from pop
    unpivot
       ( 
            code_value  for code_name in (CDE_VAL_1, CDE_VAL_2, CDE_VAL_3, CDE_VAL_4, CDE_VAL_5)
        )
    ),
    match as (
    select distinct pop_unpivot.id,ivs.codes  
    from pop_unpivot,ivs where pop_unpivot.code_value=ivs.codes
    )
select pop.*,ivs.* from match,pop,ivs where match.id=pop.id and match.codes=ivs.codes;

【讨论】:

    猜你喜欢
    • 2018-05-09
    • 1970-01-01
    • 2012-09-04
    • 1970-01-01
    • 2015-02-07
    • 1970-01-01
    • 2021-09-20
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多