Передать значение подзапроса в оператор IN - PullRequest
0 голосов
/ 06 января 2020

В одной таблице с именем prefs у меня есть столбец с именем «Value» типа clob, который содержит это значение: 'T', 'L'

Screenshot showing prefs record which holds lookup values

Мне нужно запросить таблицу serveance_code, чтобы получить записи, в которых значения столбца att_code равны T или L. Столбец att_code имеет тип varchar2.

В качестве ручного запроса модели это прекрасно работает:

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

Result:
  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: inconsistent datatypes: expected - got CLOB
00932. 00000 -  "inconsistent datatypes: expected %s got %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: inconsistent datatypes: expected - got CLOB
00932. 00000 -  "inconsistent datatypes: expected %s got %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: 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.

Я также пытался изменить значение в таблице prefs на T, L (удаляя одинарные кавычки) и запустив все вышеперечисленное, но безрезультатно.

Какой правильный способ сделай это, пожалуйста?

Ответы [ 2 ]

1 голос
/ 06 января 2020

Не хранить значения с разделителями в строке; поместите их в другую таблицу (где вы можете иметь одну строку на элемент) с внешним ключом, ссылающимся на строку в родительской таблице (например: 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' );

Какие выходные данные:

|   ID |
| ---: |
| 4903 |
| 4901 |

db <> Fiddle здесь

1 голос
/ 06 января 2020

Вы можете использовать hierarchical query с удаленными одинарными кавычками следующим образом:

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>

Приветствия !!

...