从表中选择WHERE子句中的Varying IN列表

eat*_*ode 9 sql oracle where-in xmltable

我正在处理我正在处理的项目中的问题,我不能给你实际的代码,但我已经创建了一个可执行的示例代码,如下所示

这里temptemp_id两个表

  1. temp table包含以逗号分隔的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);
Run Code Online (Sandbox Code Playgroud)

此查询不起作用

SELECT * FROM temp_id WHERE data_id IN (SELECT to_number(COLUMN_VALUE) FROM XMLTABLE(SELECT ids FROM temp));
Run Code Online (Sandbox Code Playgroud)

工作查询

SELECT * FROM temp_id WHERE data_id IN (SELECT to_number(COLUMN_VALUE) FROM XMLTABLE('1, 2, 3'));
Run Code Online (Sandbox Code Playgroud)

上面两个查询之间的差异是我temp在第一个查询中使用表中的列,并varchar2在第二个查询中直接引用.没有理由不起作用?我错过了什么吗?我认为可能存在一些数据类型不匹配但无法弄清楚.

Lal*_*r B 7

您的要求称为Varying IN-lists.请参阅WHERE子句中的Varying IN值列表

原因: IN ('1, 2, 3')一样的IN (1, 2, 3)ORIN('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
Run Code Online (Sandbox Code Playgroud)

与...不一样

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
Run Code Online (Sandbox Code Playgroud)

方案:

根据您的要求,您可以像这样实现 -

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
Run Code Online (Sandbox Code Playgroud)

或者,您可以创建自己的TABLE函数Pipelined函数来实现此目的.您的目标应该是将逗号分隔的IN列表拆分为多行.你是怎么做的取决于你!

工作演示

我们以模式中的标准EMP表为例SCOTT.

我有一个字符串中的作业列表,我想计算这些工作的员工:

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.
Run Code Online (Sandbox Code Playgroud)

哦! 发生了什么?标准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.
Run Code Online (Sandbox Code Playgroud)