将子查询的值传递给IN语句

huangapple go评论125阅读模式
英文:

Pass subquery value to IN statement

问题

在一个名为prefs的表中,我有一个名为"Value"的列,类型为clob,其中包含这个值:'T','L'

我需要查询attendance_code表,以检索att_code列的值为T或L的记录。att_code列的类型为varchar2。

作为手动模型查询,这个查询是有效的:

SELECT id FROM attendance_code ac WHERE ac.att_code IN ('T', 'L')

结果:
  ID
1 4903
2 4901

尝试1

SELECT id FROM attendance_code ac WHERE ac.att_code IN (SELECT value from prefs WHERE name = 'AEADS|SAR|tdyCodes')

ORA-00932: 数据类型不一致:期望 - 得到 CLOB
00932. 00000 - "不一致的数据类型:期望 %s 得到 %s"

尝试2

SELECT id FROM attendance_code ac WHERE ac.att_code IN (SELECT dbms_lob.substr(value, 4000, 1) from prefs WHERE name = 'AEADS|SAR|tdyCodes')

这不会产生错误,但也不会返回任何行。

尝试3
(基于 https://blogs.oracle.com/aramamoo/how-to-split-comma-separated-string-and-pass-to-in-clause-of-select-statement)

select id from attendance_code ac where ac.att_code IN (
    select regexp_substr(value,'[^,]+', 1, level) from prefs WHERE name = 'AEADS|SAR|tdyCodes' 
    connect by regexp_substr(value, '[^,]+', 1, level) is not null );
                                  
ORA-00932: 数据类型不一致:期望 - 得到 CLOB
00932. 00000 - "不一致的数据类型:期望 %s 得到 %s"

尝试4

select id from attendance_code ac where ac.att_code IN (
    select regexp_substr(dbms_lob.substr(value, 4000, 1),'[^,]+', 1, level) from prefs WHERE name = 'AEADS|SAR|tdyCodes' 
    connect by regexp_substr(dbms_lob.substr(value, 4000, 1), '[^,]+', 1, level) is not null );
                                  
ORA-06502: PL/SQL:数值或值错误:字符串缓冲区太小
ORA-06512:位于第 1 
06502. 00000 - "PL/SQL:数值或值错误%s"
*原因:发生了算术、数值、字符串、转换或约束错误。例如,如果尝试将值 NULL 分配给声明为 NOT NULL 的变量,或者尝试将大于 99 的整数分配给声明为 NUMBER(2) 的变量,就会发生此错误。
*操作:更改数据、操作数据的方式或声明数据的方式,以使值不违反约束。

我还尝试将prefs表中的值更改为T,L(删除单引号),然后运行上述所有查询,但无济于事。

请问正确的做法是什么?

英文:

In one table named prefs, I have a column named "Value" of type clob that holds this value: 'T', 'L'

将子查询的值传递给IN语句

I need to query table attendance_code to retrieve the records where column att_code values are either T or L. The att_code column is of type varchar2.

As a manual model query, this works fine:

SELECT id FROM attendance_code ac WHERE ac.att_code IN ('T', 'L')

Result:
  ID
1 4903
2 4901

Attempt 1

SELECT id FROM attendance_code ac WHERE ac.att_code IN (SELECT value from prefs WHERE name = 'AEADS|SAR|tdyCodes')

ORA-00932: inconsistent datatypes: expected - got CLOB
00932. 00000 -  "inconsistent datatypes: expected %s got %s"

Attempt 2

SELECT id FROM attendance_code ac WHERE ac.att_code IN (SELECT dbms_lob.substr(value, 4000, 1) from prefs WHERE name = 'AEADS|SAR|tdyCodes')

This yields no error, but returns no rows.

Attempt 3
(Based on https://blogs.oracle.com/aramamoo/how-to-split-comma-separated-string-and-pass-to-in-clause-of-select-statement)


select id from attendance_code ac where ac.att_code IN (
    select regexp_substr(value,'[^,]+', 1, level) from prefs WHERE name = 'AEADS|SAR|tdyCodes' 
    connect by regexp_substr(value, '[^,]+', 1, level) is not null );
                                  
ORA-00932: inconsistent datatypes: expected - got CLOB
00932. 00000 -  "inconsistent datatypes: expected %s got %s"

Attempt 4


select id from attendance_code ac where ac.att_code IN (
    select regexp_substr(dbms_lob.substr(value, 4000, 1),'[^,]+', 1, level) from prefs WHERE name = 'AEADS|SAR|tdyCodes' 
    connect by regexp_substr(dbms_lob.substr(value, 4000, 1), '[^,]+', 1, level) is not null );
                                  
ORA-06502: PL/SQL: numeric or value error: character string buffer too small
ORA-06512: at line 1
06502. 00000 -  "PL/SQL: numeric or value error%s"
*Cause:    An arithmetic, numeric, string, conversion, or constraint error
           occurred. For example, this error occurs if an attempt is made to
           assign the value NULL to a variable declared NOT NULL, or if an
           attempt is made to assign an integer larger than 99 to a variable
           declared NUMBER(2).
*Action:   Change the data, how it is manipulated, or how it is declared so
           that values do not violate constraints.

I have also tried changing the value in the prefs table to just T,L (removing the single quotes) and running all of the above against that, to no avail.

What is the proper way to do this, please?

答案1

得分: 1

您可以使用带有去除单引号分层查询,如下所示:

SELECT ID
FROM ATTENDANCE_CODE AC
WHERE AC.ATT_CODE IN (
    SELECT
        REPLACE(TRIM(REGEXP_SUBSTR(
        (SELECT value FROM prefs WHERE name = 'AEADS|SAR|tdyCodes'), 
        '[^,]+', 1, LEVEL)), '', '') FROM DUAL
    CONNECT BY REGEXP_SUBSTR(
        (SELECT value FROM prefs WHERE name = 'AEADS|SAR|tdyCodes'), 
        '[^,]+', 1, LEVEL) IS NOT NULL
);

或者使用CTE简化上面的查询,如下所示:

WITH DATAA (VALS) AS (
    SELECT VALUE
    FROM PREFS
    WHERE NAME = 'AEADS|SAR|tdyCodes'
)
SELECT ID
FROM ATTENDANCE_CODE AC,
     DATAA D
WHERE AC.ATT_CODE IN (
    SELECT
        REPLACE(TRIM(REGEXP_SUBSTR(D.VALS, '[^,]+', 1, LEVEL)), '', '')
    FROM DUAL
    CONNECT BY
        REGEXP_SUBSTR(D.VALS, '[^,]+', 1, LEVEL) IS NOT NULL
);

使用Dual的示例如下:

SQL> SELECT DUMMY FROM DUAL AC
2  WHERE
3      'T' IN (
4          SELECT
5              REPLACE(TRIM(REGEXP_SUBSTR(
6              (SELECT q'#T#', 'L'#' FROM DUAL), '[^,]+', 1, LEVEL)), '', '')
7              FROM DUAL
8          CONNECT BY
9              REGEXP_SUBSTR((
10                  SELECT q'#T#', 'L'#' FROM DUAL), '[^,]+', 1, LEVEL) IS NOT NULL
11      );

DUMMY
-------
X

SQL>

祝好!

英文:

You can use hierarchical query with removed single quotes as follows:

SELECT ID
FROM ATTENDANCE_CODE AC
WHERE AC.ATT_CODE IN (
        SELECT
            REPLACE(TRIM(REGEXP_SUBSTR(
            (SELECT value from prefs WHERE name = 'AEADS|SAR|tdyCodes'), 
            '[^,]+', 1, LEVEL)), '''', '') FROM DUAL
        CONNECT BY REGEXP_SUBSTR(
            (SELECT value from prefs WHERE name = 'AEADS|SAR|tdyCodes'), 
            '[^,]+', 1, LEVEL) IS NOT NULL
    );

or simplify the above query with the CTE as following:

WITH DATAA ( VALS ) AS (
    SELECT VALUE
      FROM PREFS
     WHERE NAME = 'AEADS|SAR|tdyCodes'
)
SELECT ID
FROM ATTENDANCE_CODE AC,
     DATAA D
WHERE AC.ATT_CODE IN (
        SELECT
            REPLACE(TRIM(REGEXP_SUBSTR(D.VALS, '[^,]+', 1, LEVEL)), '''', '')
        FROM DUAL
        CONNECT BY
            REGEXP_SUBSTR(D.VALS, '[^,]+', 1, LEVEL) IS NOT NULL
    );

Example with Dual as following:

> SQL> SELECT DUMMY FROM DUAL AC
> 2 WHERE
> 3 'T' IN (
> 4 SELECT
> 5 REPLACE(TRIM(REGEXP_SUBSTR(
> 6 (SELECT q'#'T', 'L'#' FROM DUAL), '[^,]+', 1, LEVEL)), '''', '')
> 7 FROM DUAL
> 8 CONNECT BY
> 9 REGEXP_SUBSTR((
> 10 SELECT q'#'T', 'L'#' FROM DUAL), '[^,]+', 1, LEVEL) IS NOT NULL
> 11 );
>
> DUMMY
> -------
> X
>
> SQL>

Cheers!!

答案2

得分: 1

不要将分隔的数值存储在一个字符串中;将它们放入另一个表格中(其中每个项目可以有一行),并使用外键引用父表中的行(例如:db<>fiddle),或者使用一个集合和一个嵌套表。

这第二种选项的一个示例是:

CREATE TYPE char_list IS TABLE OF CHAR(1);

然后

CREATE TABLE prefs (
  id   NUMBER(10,0) PRIMARY KEY,
  name VARCHAR2(50) NOT NULL UNIQUE,
  SchoolId NUMBER(10,0),
  UserId   NUMBER(10,0),
  Value    char_list,
  YearID   NUMBER(4,0)
) NESTED TABLE value STORE AS prefs__value;

因此,对于您的示例数据:

INSERT INTO prefs ( id, name, schoolId, UserId, value, YearID )
VALUES ( 262806, 'AEADS|SAR|tdyCodes', 109, 0, char_list( 'T', 'L' ), 29 );

CREATE TABLE attendance_code ( id, att_code ) AS
SELECT 4903, 'L' FROM DUAL UNION ALL
SELECT 4902, 'X' FROM DUAL UNION ALL
SELECT 4901, 'T' FROM DUAL;

您的查询将是:

SELECT *
FROM   attendance_code
WHERE  att_code MEMBER OF ( SELECT value FROM prefs WHERE name = 'AEADS|SAR|tdyCodes' );

输出结果如下:

> <pre>
> | ID |
> | ---: |
> | 4903 |
> | 4901 |
> </pre>

db<>fiddle 链接在此

英文:

Don't store delimited values in a string; put them in another table (where you can have one row per item) with a foreign key referencing to the row in the parent table (for example: db<>fiddle) or use a collection and a nested table.

An example of this second option is:

CREATE TYPE char_list IS TABLE OF CHAR(1);

Then

CREATE TABLE prefs (
  id   NUMBER(10,0) PRIMARY KEY,
  name VARCHAR2(50) NOT NULL UNIQUE,
  SchoolId NUMBER(10,0),
  UserId   NUMBER(10,0),
  Value    char_list,
  YearID   NUMBER(4,0)
) NESTED TABLE value STORE AS prefs__value;

So for your sample data:

INSERT INTO prefs ( id, name, schoolId, UserId, value, YearID )
VALUES ( 262806, &#39;AEADS|SAR|tdyCodes&#39;, 109, 0, char_list( &#39;T&#39;, &#39;L&#39; ), 29 );

CREATE TABLE attendance_code ( id, att_code ) AS
SELECT 4903, &#39;L&#39; FROM DUAL UNION ALL
SELECT 4902, &#39;X&#39; FROM DUAL UNION ALL
SELECT 4901, &#39;T&#39; FROM DUAL;

Your query would be:

SELECT *
FROM   attendance_code
WHERE  att_code MEMBER OF ( SELECT value FROM prefs WHERE name = &#39;AEADS|SAR|tdyCodes&#39; );

Which outputs:

> <pre>
> | ID |
> | ---: |
> | 4903 |
> | 4901 |
> </pre>

db<>fiddle here

huangapple
  • 本文由 发表于 2020年1月6日 19:24:19
  • 转载请务必保留本文链接:https://go.coder-hub.com/59611257.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定