[英]SELECT from table with Varying IN list in WHERE clause
我正在研究的項目中遇到問題,我無法給您實際的代碼,但是我創建了一個可執行的示例代碼,如下所示
這里temp
和temp_id
是兩個表
temp
表包含以逗號分隔的ID列表,即VARCHAR2
temp_id
表包含的實際ID為NUMBER
我想要搜索的行temp_id
通過獲取表ids
從逗號分開ID列表temp
表
//DDLs to create table
CREATE TABLE temp(ids VARCHAR2(4000));
CREATE TABLE temp_id(data_id NUMBER);
//DMLs to populate test data
INSERT INTO temp VALUES('1, 2, 3');
INSERT INTO temp_id VALUES(1);
INSERT INTO temp_id VALUES(2);
INSERT INTO temp_id VALUES(3);
INSERT INTO temp_id VALUES(4);
INSERT INTO temp_id VALUES(5);
此查詢不起作用
SELECT * FROM temp_id WHERE data_id IN (SELECT to_number(COLUMN_VALUE) FROM XMLTABLE(SELECT ids FROM temp));
工作查詢
SELECT * FROM temp_id WHERE data_id IN (SELECT to_number(COLUMN_VALUE) FROM XMLTABLE('1, 2, 3'));
上面兩個查詢之間的區別是,我在第一個查詢中使用了temp
表中的列,而在第二個查詢中使用了直接引號varchar2
。 沒有得到為什么不起作用的原因? 我缺少什么嗎? 我認為可能有一些數據類型不匹配,但無法弄清楚。
您的要求稱為“ 變型IN列表” 。 請參見WHERE子句中的IN值列表變化
原因: IN ('1, 2, 3')
是不一樣的IN (1, 2, 3)
OR IN('1', '2', '3')
因此,
SELECT * FROM temp_id WHERE data_id IN(SELECT ids from temp);
與...相同
SELECT * FROM temp_id WHERE data_id IN('1、2、3');
這會引發錯誤 ORA-01722: invalid number
-
SQL> SELECT * FROM temp_id WHERE data_id IN('1, 2, 3');
SELECT * FROM temp_id WHERE data_id IN('1, 2, 3')
*
ERROR at line 1:
ORA-01722: invalid number
SQL> SELECT * FROM temp_id WHERE data_id IN(SELECT ids FROM temp);
SELECT * FROM temp_id WHERE data_id IN(SELECT ids FROM temp)
*
ERROR at line 1:
ORA-01722: invalid number
與...不同
SELECT * FROM temp_id WHERE data_id IN(1、2、3);
這將為您提供正確的輸出-
SQL> SELECT * FROM temp_id WHERE data_id IN(1, 2, 3);
DATA_ID
----------
1
2
3
解決方案:
根據您的要求,您可以像這樣實現它-
SQL> SELECT * FROM temp;
IDS
--------------------------------------------------------------
1, 2, 3
SQL> SELECT * FROM temp_id;
DATA_ID
----------
1
2
3
4
5
SQL> WITH data AS
2 (SELECT to_number(trim(regexp_substr(ids, '[^,]+', 1, LEVEL))) ids
3 FROM temp
4 CONNECT BY instr(ids, ',', 1, LEVEL - 1) > 0
5 )
6 SELECT * FROM temp_id WHERE data_id IN
7 (SELECT ids FROM data
8 )
9 /
DATA_ID
----------
1
2
3
另外,您可以創建自己的TABLE函數或Pipelined函數來實現此目的。 您的目標應該是將以逗號分隔的IN列表分成多行 。 您的操作方式取決於您!
工作演示
讓我們以SCOTT
模式中的標准EMP表為例。
我有一個字符串工作列表,我想計算這些工作的員工數:
SQL> SET serveroutput ON
SQL> DECLARE
2 str VARCHAR2(100);
3 cnt NUMBER;
4 BEGIN
5 str := q'[CLERK,SALESMAN,ANALYST]';
6 SELECT COUNT(*) INTO cnt FROM emp WHERE JOB IN (str);
7 dbms_output.put_line('The total count is '||cnt);
8 END;
9 /
The total count is 0
PL/SQL procedure successfully completed.
哦! 發生了什么? 標准emp表應提供輸出10。原因是IN列表變化 。
讓我們看看正確的方法:
SQL> SET serveroutput ON
SQL> DECLARE
2 str VARCHAR2(100);
3 cnt NUMBER;
4 BEGIN
5 str := q'[CLERK,SALESMAN,ANALYST]';
6 SELECT COUNT(*)
7 INTO cnt
8 FROM emp
9 WHERE job IN
10 (SELECT trim(regexp_substr(str, '[^,]+', 1, LEVEL))
11 FROM dual
12 CONNECT BY instr(str, ',', 1, LEVEL - 1) > 0
13 );
14 dbms_output.put_line('The total count is '||cnt);
15 END;
16 /
The total count is 10
PL/SQL procedure successfully completed.
還有另一種方法可以實現,即使用LIKE
:
SELECT ti.*
FROM temp t, temp_id ti
WHERE ',' || REPLACE(t.ids, ' ') || ',' LIKE '%,' || TO_CHAR(ti.data_id) || ',%'
(我使用上面的REPLACE()
擺脫了ID列表中多余的空格-使事情變得更簡單。)或者,可以使用REGEXP_LIKE()
:
SELECT ti.*
FROM temp t, temp_id ti
WHERE REGEXP_LIKE(REPLACE(t.ids, ' '), '(^|,)' || TO_CHAR(ti.data_id) || '(,|$)')
[[脫字符號( ^
)和美元符號( $
)分別與字符串的開頭和結尾匹配-因此ID可以與字符串開頭的內容匹配(以逗號結尾或以結尾結尾)字符串開頭)或以逗號開頭的內容(再次以逗號或字符串結尾結尾)。]
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.