重写 NOT IN,但子查询涉及逗号分隔的字符串 (ID)

Posted

技术标签:

【中文标题】重写 NOT IN,但子查询涉及逗号分隔的字符串 (ID)【英文标题】:Rewrite NOT IN, but subquery involves a comma seperated string (ID) 【发布时间】:2017-07-28 10:58:34 【问题描述】:

使用 SQL Developer 更改 Oracle 存储过程。

输入:逗号分隔的 ID。 (例如:'P23,P37,P39,P45') 编辑:请注意输入是一个字符串,不是一个字符串数组。此外,字符串可能不仅仅是 4 个 ID。最高可达 200 左右。

想从没有那些输入 ID 的表中找出。

以下太慢了。大约 300 行数据(在表中)但大约需要 20 秒。所以我想重写。请给我一些关于如何做的提示。

ID_Array 是 'P23,P37,P39,P45'。

SELECT * FROM StudentInfo
WHERE StudentClass = 'Primary5A'
AND StudentID NOT IN
(
    SELECT REGEXP_SUBSTR(ID_Array, '[^,]+', 1, LEVEL) StudentID
    FROM DUAL
    CONNECT BY REGEXP_SUBSTR(ID_Array, '[^,]+', 1, LEVEL) IS NOT NULL   
)
AND Height <= 150;

你们中的一些人可能已经知道了。以下

    SELECT REGEXP_SUBSTR(ID_Array, '[^,]+', 1, LEVEL) StudentID
    FROM DUAL
    CONNECT BY REGEXP_SUBSTR(ID_Array, '[^,]+', 1, LEVEL) IS NOT NULL   

会将 ID_Array 变成一个有四行的表(类似表的结构?):

+-----+
| P23 |
| P37 |
| P39 |
| P45 |
+-----+

【问题讨论】:

硬编码需要多长时间:AND StudentID NOT IN ('P23','P37','P39','P45') AND Height &lt;= 150?两者的执行计划是什么?您的统计数据是最新的吗? 当您操作的是字符串而不是表格时,拆分逗号分隔字符串的各种方法之间几乎没有区别。我认为 Alex 建议的还有其他问题。 我对字符串进行了硬编码。执行计划:基数:184,成本:191,使用 real 数据。它对 StudentInfo 进行了全表扫描。使用下面的答案,两个执行计划都非常低(例如成本:5)。 【参考方案1】:

您的 ID_Array 必须比此处的示例长很多。 'P23,P37,P39,P45' 的表现非常好。

如果字符串较长,REGEXP_SUBSTR 会变得非常慢。我建议尽可能使用LIKE,即使它变得很奇怪。试试这个。

SELECT * FROM StudentInfo
WHERE StudentClass = 'Primary5A'
AND ','||ID_Array||',' NOT LIKE '%,'||StudentID||',%'
AND Height <= 150;

【讨论】:

是的,ID_Array 更长。花费的时间比大卫的答案要少一些,所以我“勾选”你的答案是公认的答案。谢谢。【参考方案2】:

即使您使用的是正则表达式,也无需使用CONNECT BY。您可以使用LIKE,也可以使用REGEXP_LIKE()

SELECT * FROM studentinfo
 WHERE studentclass = 'Primary5A'
   AND height <= 150
   AND NOT REGEXP_LIKE(','||id_array||',', ','||studentid||',');

我猜id_array 不够短,不能用作正则表达式模式本身(300 行?)。如果是,您可以执行以下操作:

SELECT * FROM studentinfo
 WHERE studentclass = 'Primary5A'
   AND height <= 150
   AND NOT REGEXP_LIKE(student_id, '^(' || REPLACE(id_array, ',', '|') || ')$');

但我认为,Oracle 中的正则表达式模式限制为 512 个字节。

【讨论】:

我实际上让第一个工作代替。第二个抱怨正则表达式太长。感谢您的帮助。 是的,Oracle 正则表达式限制为 512 个字节

以上是关于重写 NOT IN,但子查询涉及逗号分隔的字符串 (ID)的主要内容,如果未能解决你的问题,请参考以下文章

重写 Equals 方法时是不是需要重写 == 和 != 运算符? (。网)

两个 mod 重写规则

nginx子域重写

shiro-重写标签功能----shiro:hasPermission 标签重写

htaccess 重写。我不希望所有这些都被重写 - 如何排除某些页面?

一文就带你搞懂✨为什么重写 equals 时必须重写 hashCode 方法?