Сортировка наборов данных через запятую в строке - PullRequest
1 голос
/ 03 июля 2019

Это то, что дается

Numbers         Powers
4,5,1           WATER,FIRE
6,3,9           ICE,WATER,FIRE

Мое требование (отсортированный заказ)

Numbers               Powers
1,4,5                 FIRE,WATER
3,6,9                 FIRE,ICE,WATER .

Я хочу это в отсортированном порядке! Как это сделать в базе данных?

Ответы [ 3 ]

2 голосов
/ 03 июля 2019

Разделить столбец на строки, затем агрегировать их обратно, отсортировать.

SQL> with test (id, num, pow) as
  2    (select 1, '4,5,1', 'water,fire'     from dual union all
  3     select 2, '6,3,9', 'ice,water,fire' from dual
  4    ),
  5  temp as
  6    -- split columns to rows
  7    (select id,
  8            regexp_substr(num, '[^,]+', 1, column_value) num1,
  9            regexp_substr(pow, '[^,]+', 1, column_value) pow1
 10     from test join table(cast(multiset(select level from dual
 11                                        connect by level <= regexp_count(num, ',') + 1
 12                                       ) as sys.odcinumberlist)) on 1 = 1
 13    )
 14    -- aggregate them back, sorted
 15  select id,
 16         listagg(num1, ',') within group (order by to_number(num1)) num_result,
 17         listagg(pow1, ',') within group (order by pow1) pow_result
 18  from temp
 19  group by id;

        ID NUM_RESULT                     POW_RESULT
---------- ------------------------------ ------------------------------
         1 1,4,5                          fire,water
         2 3,6,9                          fire,ice,water

SQL>
1 голос
/ 04 июля 2019

Установка Oracle :

CREATE TABLE test_data ( Numbers, Powers ) AS
SELECT '4,5,1', 'WATER,FIRE'     FROM DUAL UNION ALL
SELECT '6,3,9', 'ICE,WATER,FIRE' FROM DUAL UNION ALL
SELECT '7',     'D,B,E,C,A'      FROM DUAL

Запрос :

SELECT (
         SELECT LISTAGG( TO_NUMBER( REGEXP_SUBSTR( t.numbers, '\d+', 1, LEVEL ) ), ',' )
                  WITHIN GROUP ( ORDER BY TO_NUMBER( REGEXP_SUBSTR( t.numbers, '\d+', 1, LEVEL ) ) )
         FROM   DUAL
         CONNECT BY LEVEL <= REGEXP_COUNT( t.numbers, ',' ) + 1
       ) AS numbers,
       (
         SELECT LISTAGG( REGEXP_SUBSTR( t.powers, '[^,]+', 1, LEVEL ), ',' )
                  WITHIN GROUP ( ORDER BY REGEXP_SUBSTR( t.powers, '[^,]+', 1, LEVEL ) )
         FROM   DUAL
         CONNECT BY LEVEL <= REGEXP_COUNT( t.powers, ',' ) + 1
       ) AS numbers
FROM   test_data t

Вывод :

NUMBERS | NUMBERS       
:------ | :-------------
1,4,5   | FIRE,WATER    
3,6,9   | FIRE,ICE,WATER
7       | A,B,C,D,E     

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

1 голос
/ 03 июля 2019

Вы можете попробовать следующее:

Я использовал таблицу, так как мне понадобится какое-то значение, чтобы получить другое значение.здесь я использовал ROWID.

SELECT
    ID,
    LISTAGG(NUM, ',') WITHIN GROUP(
        ORDER BY
            NUM
    ) AS NUM,
    LISTAGG(POW, ',') WITHIN GROUP(
        ORDER BY
            POW
    ) AS POW
FROM
    (
        SELECT
            DISTINCT ROWID,
            ID,
            REGEXP_SUBSTR(NUM, '[^,]+', 1, LEVEL) NUM,
            REGEXP_SUBSTR(POW, '[^,]+', 1, LEVEL) POW
        FROM
            TEST
        CONNECT BY REGEXP_SUBSTR(NUM, '[^,]+', 1, LEVEL) IS NOT NULL
                   OR REGEXP_SUBSTR(POW, '[^,]+', 1, LEVEL) IS NOT NULL
    )
    GROUP BY ID
    ORDER BY ID;

db <> fiddle demo

Cheers !!

---- ОБНОВЛЕНИЕ ----

Как уже упоминалось в комментарии, что он генерирует дубликаты, я перефразировал весь запрос следующим образом:

SELECT
    ID,
    LISTAGG(C_S.NUM, ',') WITHIN GROUP(
                ORDER BY
                    C_S.NUM
            ) AS NUM,
    LISTAGG(C_S.POW, ',') WITHIN GROUP(
                ORDER BY
                    C_S.POW
            ) AS POW
FROM
(SELECT
    T.ID,
    REGEXP_SUBSTR(T.NUM, '[^,]+', 1, NUMS_COMMA.COLUMN_VALUE) NUM,
    REGEXP_SUBSTR(T.POW, '[^,]+', 1, NUMS_COMMA.COLUMN_VALUE) POW
FROM
    TEST T,
    TABLE ( CAST(MULTISET(
        SELECT
            LEVEL
        FROM
            DUAL
        CONNECT BY
            LEVEL <= GREATEST(LENGTH(REGEXP_REPLACE(T.NUM, '[^,]+')),
            LENGTH(REGEXP_REPLACE(T.POW, '[^,]+'))) + 1
    ) AS SYS.ODCINUMBERLIST) ) NUMS_COMMA) C_S
 GROUP BY ID;

db <> обновленная демоверсия скрипки

Cheers !!

...