英文:
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')
这不会产生错误,但也不会返回任何行。
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'
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, '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;
Your query would be:
SELECT *
FROM attendance_code
WHERE att_code MEMBER OF ( SELECT value FROM prefs WHERE name = 'AEADS|SAR|tdyCodes' );
Which outputs:
> <pre>
> | ID |
> | ---: |
> | 4903 |
> | 4901 |
> </pre>
db<>fiddle here
通过集体智慧和协作来改善编程学习和解决问题的方式。致力于成为全球开发者共同参与的知识库,让每个人都能够通过互相帮助和分享经验来进步。
评论