Oracle 多值组

Oracle multivalue groups

我有一个带有 2 个多值字段的 table 例如:

第 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      |
|---------------------|------------------|

所以这两个字段是相关的——字段 1 的位置 2 的值与字段 2 的位置 2 的值相关。 我想做的是 update/replace 字段 2 中的一个或多个值,只有每个组中的值都相等。

例如 在第一行中,我在位置 0 中有匹配值“1”,需要在字段 2 中替换它。我该怎么做?只需提及字段 1 和字段 2 中的空值不应被视为相等,它们的存在只是为了显示位置。询问您是否需要更多信息

第一,不要用这个;而是修复您的 table 设计,使其不存储逗号分隔值。但是,如果您坚持,那么您可以使用它将 csv 拆分为单独的值,然后执行替换,然后再次聚合它们并使用 MERGE 语句更新 table 与 [= 上的更新相关联14=] 伪列.

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<>fiddle here