Многозначные группы Oracle - PullRequest
0 голосов
/ 20 февраля 2019

У меня есть таблица с 2 полями с несколькими значениями, например:

1-я строка содержит эти поля:

поле 1: 1,4,5

поле 2:1,2,3

второй ряд содержит:

поле 1: 5,6,7

поле 2:, 6,3

третий ряд:

поле 1: 8,, 9

поле 2: 1,, 3

|---------------------|------------------|
|      column 1       |     column 2     |
|---------------------|------------------|
|       1,4,5         |       1,2,3      |
|---------------------|------------------|
|       5,6,7         |       ,6,3       |
|---------------------|------------------|
|       8,,9          |        1,,3      |
|---------------------|------------------|

Таким образом, оба поля находятся в отношении - значение в позиции 2 поля1 относится к значению в позиции 2 поля field2.Я хочу обновить / заменить одно или несколько значений в поле 2, только для которых значения в каждой группе равны.

Например, в первой строке у меня совпадающее значение '1'в позиции 0, которую нужно заменить в поле 2. Как я мог это сделать?Просто отметим, что нулевые значения из поля 1 и поля 2 не должны рассматриваться как равные, они просто показывают положение.Спросите, если вам нужна дополнительная информация

1 Ответ

0 голосов
/ 20 февраля 2019

Во-первых, не используйте это;вместо этого исправьте дизайн таблицы, чтобы не хранить значения, разделенные запятыми.Однако, если вы настаиваете, вы можете использовать это для разделения CSV на отдельные значения, затем выполнить замену, а затем снова объединить их и использовать оператор MERGE для обновления таблицы, коррелирующей обновление с псевдостолбцом ROWID.

Установка Oracle :

CREATE TABLE test_data ( column1 VARCHAR2(20), column2 VARCHAR2(20) );

INSERT INTO test_data ( column1, column2 )
SELECT '1,4,5', '1,2,3' FROM DUAL UNION ALL
SELECT '5,6,7', ',6,3'  FROM DUAL UNION ALL
SELECT '8,,9', '1,,3'   FROM DUAL UNION ALL
SELECT '1,4,5', '3,4,5' FROM DUAL;

Выполнить замену :

Это добавляет 10 к каждому значению column2, где оно соответствует column1.

MERGE INTO test_data dst
USING ( 
  SELECT rid,
         REPLACE(
           LISTAGG(
             COALESCE( TO_CHAR( column1 ), '#' ),
             ','
           ) WITHIN GROUP ( ORDER BY idx ),
           '#'
         )AS column1,
         REPLACE(
           LISTAGG(
             COALESCE( TO_CHAR( CASE column2 WHEN column1 THEN column2 + 10 ELSE column2 END ), '#' ),
             ','
           ) WITHIN GROUP ( ORDER BY idx ),
           '#'
         ) AS column2
  FROM   (
    SELECT t.ROWID AS rid,
           COLUMN_VALUE AS idx,
           TO_NUMBER( REGEXP_SUBSTR( t.column1, '(\d*)(,|$)', 1, COLUMN_VALUE, NULL, 1 ) ) AS column1,
           TO_NUMBER( REGEXP_SUBSTR( t.column2, '(\d*)(,|$)', 1, COLUMN_VALUE, NULL, 1 ) ) AS column2
    FROM   test_data t
           CROSS JOIN
           TABLE(
             CAST(
               MULTISET(
                 SELECT LEVEL
                 FROM   DUAL
                 CONNECT BY LEVEL < REGEXP_COUNT( t.column1, '(\d*)(,|$)' )
               )
               AS SYS.ODCINUMBERLIST
             )
           ) l
  )
  GROUP BY rid
) src
ON ( dst.ROWID = src.RID )
WHEN MATCHED THEN
  UPDATE SET column2 = src.column2 WHERE src.column2 <> dst.column2;

Выход :

SELECT * FROM test_data;
COLUMN1 | COLUMN2
:------ | :------
1,4,5   | 11,2,3 
5,6,7   | ,16,3  
8,,9    | 1,,3   
1,4,5   | 3,14,15

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

...