Использование многослойного столбца в качестве ссылки на внешний ключ - PullRequest
0 голосов
/ 22 февраля 2020

У меня есть таблица TABLEA, в которой хранятся данные в столбцах, которые в основном состоят из многоуровневых столбцов, таких как ColumnA ', 2562,2563,2564,' и ColumnB со значениями ',121,122,123,'. Эти столбцы на самом деле являются значениями внешнего ключа, поступающими из другой таблицы.

Данные в Таблице А выглядят примерно так.

ID NAME   ColumnA           ColumnB
1  ITEM1  ,2562,2563,2564,  ,121,122,123
2  ITEM2  NULL              ,6455,545,
3  ITEM3  ,1221,1546,       NULL
4  ITEM4  NULL              NULL

Я хочу объединить эти столбцы с родительскими таблицами и извлечь данные. Я надеюсь, что в наборе результатов будет 8 строк. Например,

ITEM   ColumnA   ColumB
ITEM1  2562      121
ITEM1  2563      122
ITEM1  2564      123
ITEM2  NULL      6455
ITEM2  NULL      545
....

Я пробовал этот запрос с некоторой помощью, но он не работает, когда я пытаюсь использовать ColumnB, а также игнорирует элементы со значениями NULL. Столбец A сохраняет идентификаторы таблицы USER_GROUP, но ColumnB выбирает идентификаторы из некоторой другой таблицы, скажем, GROUP1, и может существовать другой столбец ColumnC, который может хранить значения из другой таблицы, так что такая ситуация Я застрял и надеюсь, что объяснил, чтобы кто-то мог понять, но я открыт, если вы хотите, чтобы я улучшил больше

SELECT ug.*
FROM USER_GROUP ug
WHERE EXISTS (SELECT 1
              FROM TableA t1
              WHERE t1.COLUMNA LIKE '%,' || ug.ID || ',%'
             )
AND EXISTS (SELECT 1
              FROM TableA t1
              WHERE t1.COLUMNB LIKE '%,' || ug.ID || ',%'
             );

Ответы [ 2 ]

1 голос
/ 22 февраля 2020

Вам не нужно использовать (медленные) регулярные выражения, и вы можете сделать это с помощью простых строковых функций в предложении рекурсивного факторинга подзапроса:

WITH split_data ( id, name, columna, columnb, starta, enda, startb, endb ) AS (
  SELECT id,
         name,
         columna,
         columnb,
         INSTR(columna,',',1,1),
         INSTR(columna,',',1,2),
         INSTR(columnb,',',1,1),
         INSTR(columnb,',',1,2)
  FROM   test_data
UNION ALL
  SELECT id,
         name,
         columna,
         columnb,
         enda,
         CASE WHEN enda = 0 THEN 0 ELSE INSTR(columna,',',enda+1,1) END,
         endb,
         CASE WHEN endb = 0 THEN 0 ELSE INSTR(columnb,',',endb+1,1) END
  FROM   split_data
  WHERE  enda > 0
  OR     endb > 0
)
SELECT id,
       name,
       CASE
       WHEN starta = 0 THEN NULL
       WHEN enda = 0 THEN SUBSTR( columna, starta + 1 )
       ELSE SUBSTR( columna, starta + 1, enda - starta - 1 )
       END AS valuea,
       CASE
       WHEN startb = 0 THEN NULL
       WHEN endb = 0 THEN SUBSTR( columnb, startb + 1 )
       ELSE SUBSTR( columnb, startb + 1, endb - startb - 1 )
       END as valueb
FROM   split_data
ORDER BY id, starta, startb;

Что для ваших тестовых данных:

CREATE TABLE test_data ( ID, NAME, ColumnA, ColumnB ) AS
SELECT 1, 'ITEM1', ',2562,2563,2564', ',121,122,123' FROM DUAL UNION ALL
SELECT 2, 'ITEM2', NULL,              ',6455,545' FROM DUAL UNION ALL
SELECT 3, 'ITEM3', ',1221,1546',      NULL FROM DUAL UNION ALL
SELECT 4, 'ITEM4', NULL,              NULL FROM DUAL;

Выходы:

ID | NAME  | VALUEA | VALUEB
-: | :---- | :----- | :-----
 1 | ITEM1 | 2562   | 121   
 1 | ITEM1 | 2563   | 122   
 1 | ITEM1 | 2564   | 123   
 2 | ITEM2 | <em>null</em>   | 6455  
 2 | ITEM2 | <em>null</em>   | 545   
 3 | ITEM3 | 1221   | <em>null</em>  
 3 | ITEM3 | 1546   | <em>null</em>  
 4 | ITEM4 | <em>null</em>   | <em>null</em>  

дБ <> скрипка здесь

1 голос
/ 22 февраля 2020

Вот один из вариантов:

SQL> with test (id, name, cola, colb) as
  2    (select 1, 'item1', ',2562,2563,2564,', ',121,122,123,' from dual union all
  3     select 2, 'item2', null              , ',6455,545,'    from dual union all
  4     select 3, 'item3', ',1221,1546,'     , null            from dual union all
  5     select 4, 'item4', null              , null            from dual
  6    ),
  7  remcom
  8    -- remove leading and trailing commas
  9  as (select id,
 10        name,
 11        rtrim(ltrim(cola, ','), ',') cola,
 12        rtrim(ltrim(colb, ','), ',') colb
 13      from test
 14     )
 15  select id,
 16    name,
 17    regexp_substr(cola, '[^,]+', 1, column_value) cola,
 18    regexp_substr(colb, '[^,]+', 1, column_value) colb
 19  from remcom r cross join
 20    table(cast(multiset(select level from dual
 21                        connect by level <= regexp_count(nvl(r.cola, r.colb), ',') + 1
 22                       ) as sys.odcinumberlist))
 23  order by id, name, cola, colb;

        ID NAME  COLA       COLB
---------- ----- ---------- ----------
         1 item1 2562       121
         1 item1 2563       122
         1 item1 2564       123
         2 item2            545
         2 item2            6455
         3 item3 1221
         3 item3 1546
         4 item4

8 rows selected.

SQL>

Теперь, когда он у вас есть, объедините этот результат с другой таблицей, которая у вас есть.

Кстати, этот пример хорошо показывает, что это плохо Идея хранить несколько значений в одном столбце. Не делай этого.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...