【发布时间】:2019-10-17 19:19:19
【问题描述】:
我在工作中学习 Oracle SQL,并且正在寻找一些(理想情况下紧凑且高效的)条件表达式,如果列表 A 中的任何项目出现在列表 B 中,则该条件表达式的计算结果为真。
我有一个表IVS,其中包含一列值CODES,还有一个表POP,其中包含一组列(CDE_VAL_1 到CDE_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 语句以获取一些示例数据,然后提供该数据的预期输出(以及从输入到输出的必要逻辑细节)。它可能有助于我们了解您想要实现的目标,因为代码本身对于您期望它如何转换数据相当混乱。