簡體   English   中英

從帶有WHERE子句中的IN列表變化的表中進行SELECT

[英]SELECT from table with Varying IN list in WHERE clause

我正在研究的項目中遇到問題,我無法給您實際的代碼,但是我創建了一個可執行的示例代碼,如下所示

這里temptemp_id是兩個表

  1. temp表包含以逗號分隔的ID列表,即VARCHAR2
  2. 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.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM