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

Rewrite NOT IN, but subquery involves a comma seperated string (ID)

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

输入:逗号分隔的 ID。 (示例:'P23,P37,P39,P45') 编辑:请注意输入的是字符串,不是字符串数组。此外,该字符串可能不仅仅是 4 个 ID。可能会上升到 200 左右。

想从没有这些输入 ID 的 table 中找出。

以下太慢了。只有大约 300 行数据(在 table 中)但需要大约 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 变成一个 table(table 类结构?)有四行:

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

你的 ID_Array 一定比你这里的例子长很多。 'P23,P37,P39,P45' 我的表现非常好。

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

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

即使您使用的是正则表达式,也无需使用 CONNECT BY。您可以使用 LIKEREGEXP_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 个字节。