从 SQL 中的列表列中获取不同的排序列表?

Get distinct, sorted list from column of lists in SQL?

我有一个 SQL table 如下所示:

Field1,Field2
AAAA,111;222
AAAA,222;333
AAAA,333;444
BBBB,999;000

如何将这一行仅作为升序值列表?

Field1,Field2
AAAA,111;222;333;444
BBBB,000;999

这是一种选择:

示例数据:

SQL> with test (field1, field2) as
  2  (select 'AAAA', '111;222' from dual union all
  3   select 'AAAA', '222;333' from dual union all
  4   select 'AAAA', '333;444' from dual union all
  5   select 'BBBB', '999;000' from dual
  6  ),

首先将field2拆分成行; distinct 将消除重复;然后使用 listagg:

聚合它们
  7  temp as
  8    (select distinct
  9       field1,
 10       regexp_substr(field2, '[^;]+', 1, column_value) f2
 11     from test cross join
 12       table(cast(multiset(select level from dual
 13                           connect by level <= regexp_count(field2, ';') + 1
 14                          ) as sys.odcinumberlist))
 15    )
 16  select field1,
 17         listagg(f2, ';') within group (order by f2) field2
 18  from temp
 19  group by field1;

FIEL FIELD2
---- ------------------------------
AAAA 111;222;333;444
BBBB 000;999

SQL>

您可以使用简单(快速)字符串函数(而不是慢速正则表达式)来完成此操作:

WITH split_fields (field1, field2, spos, epos) AS (
  SELECT field1, field2, 1, INSTR(field2, ';', 1)
  FROM   table_name
UNION ALL
  SELECT field1, field2, epos + 1, INSTR(field2, ';', epos + 1)
  FROM   split_fields
  WHERE  epos > 0
),
items (field1, item) AS (
  SELECT DISTINCT
         field1,
         CASE epos
         WHEN 0
         THEN SUBSTR(field2, spos)
         ELSE SUBSTR(field2, spos, epos - spos)
         END
  FROM   split_fields
)
SELECT field1,
       LISTAGG(item, ';') WITHIN GROUP (ORDER BY item) AS field2
FROM   items
GROUP BY field1

其中,对于示例数据:

CREATE TABLE table_name (Field1, Field2) AS
SELECT 'AAAA', '111;222' FROM DUAL UNION ALL
SELECT 'AAAA', '222;333' FROM DUAL UNION ALL
SELECT 'AAAA', '333;444' FROM DUAL UNION ALL
SELECT 'BBBB', '999;000' FROM DUAL;

输出:

FIELD1 FIELD2
AAAA 111;222;333;444
BBBB 000;999

db<>fiddle here

您可以使用正则表达式拆分 FIELD2 值,然后使用 LISTAGG 将它们放回原处:

WITH cteSubfields
  AS (SELECT DISTINCT FIELD1, REGEXP_SUBSTR(FIELD2, '[^;]+', 1, LEVEL) AS SUBFIELD
        FROM TEST_TABLE
        CONNECT BY LEVEL <= REGEXP_COUNT(FIELD2, ';')+1)
SELECT DISTINCT FIELD1,
                LISTAGG(SUBFIELD, ',') OVER (PARTITION BY FIELD1) AS FIELD2
  FROM cteSubfields

db<>fiddle here