2017-07-28 97 views
0

使用SQL Developer更改Oracle存儲過程。重寫NOT IN,但子查詢使用逗號分隔的字符串(ID)

輸入:用逗號分隔的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 | 
+-----+ 
+2

如果您對其進行硬編碼,需要多長時間:AND St​​udentID NOT IN('P23','P37','P39','P45')和高度<= 150'?兩者的執行計劃都顯示了什麼?你的統計數據是最新的嗎? –

+0

由於您使用的是字符串而不是表格,因此拆分逗號分隔字符串的各種方法之間幾乎沒有區別。我認爲Alex的建議還有其他錯誤。 – Ben

+0

我硬編碼的字符串。執行計劃:基數:184,成本:191使用_real_數據。它在StudentInfo上進行全表掃描。使用下面的答案,兩個執行計劃都非常低(如成本:5)。 – user3454439

回答

2

你ID_Array一定比這裏你的榜樣長得多。 'P23,P37,P39,P45'的表現非常出色。

如果字符串較長,REGEXP_SUBSTR會變得非常慢。我建議儘可能使用LIKE,即使它變得奇怪。試試這個。

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

是的,ID_Array時間更長。所花費的時間比戴維的回答要少一些,所以我打勾你的答案。謝謝。 – user3454439

1

即使使用正則表達式,也不需要使用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, ',', '|') || ')$'); 

但經常在甲骨文表達模式是有限的,我認爲,爲512個字節。

+0

我實際上得到了第一個工作。第二個抱怨正則表達式太長。謝謝你的幫助。 – user3454439

+0

是的,Oracle正則表達式被限制爲512字節 –