Разделить данные одного столбца на несколько столбцов в Oracle - PullRequest
0 голосов
/ 08 мая 2018

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

SELECT columnC
     , LISTAGG(r.columnA,',') WITHIN GROUP (ORDER BY r.columnB) AS Test_sensor
  FROM tableA
 GROUP BY columnC

В настоящее время вывод выглядит следующим образом -

ColumnC  |  Test_Sensor
=============================
Z12345   |  20,30,40,50,60,70

Но яхотите, чтобы эти данные отображались, как показано ниже -

ColumnC  |  Test_Sensor1 |  Test_Sensor2 |   Test_Sensor3  |  Test_Sensor4
==========================================================================
Z12345   |  20           |   30          |    40           |  50   

Пожалуйста, помогите мне в этом

Спасибо Kranthi RTR

Ответы [ 2 ]

0 голосов
/ 08 мая 2018

Если вы используете LISTAGG, есть предостережение с LISTAGG в том, что он игнорирует значения NULL. Вы уверены, что ваша колонка ВСЕГДА будет иметь данные? Если, скажем, test_sensor2 равен NULL, выходной результат операции listagg будет 20,40,50,60,70, поэтому после значения NULL все данные датчика будут сообщены неверно! Исправьте это, используя это:

replace(LISTAGG( nvl(to_char(ColumnA), ','), ',' ) 
        WITHIN GROUP ( ORDER BY ColumnB ), ',,,',',,')

Теперь ваш вывод равен 20,,40,50,60,70, сохраняя значение NULL для test_sensor2, а остальные в правильном положении.

ОДНАКО теперь существует другая проблема в том, что регулярное выражение формы '[^,]+' вызывает ту же проблему! Таким образом, даже несмотря на то, что вывод listagg фиксирован, анализируемый вывод снова отключается после столбца со значением NULL! Ниже показана другая форма, которая решает эту проблему. Вот пример, настроенный таким образом, что вы можете комментировать / раскомментировать, чтобы увидеть различия при обработке данных. Всегда ожидай неожиданного!

with TableA ( ColumnA, ColumnB, ColumnC ) AS (
  SELECT 20, 'A', 'Z12345' FROM DUAL UNION ALL
  SELECT NULL, 'B', 'Z12345' FROM DUAL UNION ALL -- make NULL
  SELECT 40, 'C', 'Z12345' FROM DUAL UNION ALL
  SELECT 50, 'D', 'Z12345' FROM DUAL UNION ALL
  SELECT 60, 'E', 'Z12345' FROM DUAL UNION ALL
  SELECT 70, 'F', 'Z12345' FROM DUAL
),
tbl_tmp as (
  SELECT ColumnC,
         -- Preserve the NULL in position 2
         replace(LISTAGG( nvl(to_char(ColumnA), ','), ',' ) 
                 WITHIN GROUP ( ORDER BY ColumnB ), ',,,',',,')
           AS test_sensor
  FROM   TableA
  GROUP BY ColumnC
)
--select * from tbl_tmp;
-- regex of format [^,]+ does not handle NULLs
SELECT ColumnC,
--       REGEXP_SUBSTR( test_sensor, '[^,]+', 1, 1) AS test_sensor1,  
--       REGEXP_SUBSTR( test_sensor, '[^,]+', 1, 2 ) AS test_sensor2,
--       REGEXP_SUBSTR( test_sensor, '[^,]+', 1, 3 ) AS test_sensor3,
--       REGEXP_SUBSTR( test_sensor, '[^,]+', 1, 4 ) AS test_sensor4
       REGEXP_SUBSTR( test_sensor, '(.*?)(,|$)', 1, 1, NULL, 1) AS test_sensor1,
       REGEXP_SUBSTR( test_sensor, '(.*?)(,|$)', 1, 2, NULL, 1 ) AS test_sensor2,
       REGEXP_SUBSTR( test_sensor, '(.*?)(,|$)', 1, 3, NULL, 1 ) AS test_sensor3,
       REGEXP_SUBSTR( test_sensor, '(.*?)(,|$)', 1, 4, NULL, 1 ) AS test_sensor4
FROM  tbl_tmp;
0 голосов
/ 08 мая 2018

Вы можете использовать PIVOT (и не нужно использовать LISTAGG):

SQL Fiddle

Настройка схемы Oracle 11g R2 :

CREATE TABLE TableA ( ColumnA, ColumnB, ColumnC ) AS
  SELECT 20, 'A', 'Z12345' FROM DUAL UNION ALL
  SELECT 30, 'B', 'Z12345' FROM DUAL UNION ALL
  SELECT 40, 'C', 'Z12345' FROM DUAL UNION ALL
  SELECT 50, 'D', 'Z12345' FROM DUAL UNION ALL
  SELECT 60, 'E', 'Z12345' FROM DUAL UNION ALL
  SELECT 70, 'F', 'Z12345' FROM DUAL;

Запрос 1 :

SELECT *
from (
  SELECT columnA,
         columnC,
         ROW_NUMBER() OVER ( PARTITION BY columnC ORDER BY columnB ) AS rn
  FROM   tableA
) a
PIVOT ( MAX( columnA ) FOR rn IN (
  1 AS test_sensor1,
  2 AS test_sensor2,
  3 AS test_sensor3,
  4 AS test_sensor4
) )

Результаты :

| COLUMNC | TEST_SENSOR1 | TEST_SENSOR2 | TEST_SENSOR3 | TEST_SENSOR4 |
|---------|--------------|--------------|--------------|--------------|
|  Z12345 |           20 |           30 |           40 |           50 |

Запрос 2 :

Вы можете сделать это, используя LISTAGG, но это намного, намного менее эффективно, чем PIVOT:

SELECT ColumnC,
       REGEXP_SUBSTR( test_sensor, '[^,]+', 1, 1 ) AS test_sensor1,
       REGEXP_SUBSTR( test_sensor, '[^,]+', 1, 2 ) AS test_sensor2,
       REGEXP_SUBSTR( test_sensor, '[^,]+', 1, 3 ) AS test_sensor3,
       REGEXP_SUBSTR( test_sensor, '[^,]+', 1, 4 ) AS test_sensor4
FROM   (
  SELECT ColumnC,
         LISTAGG( ColumnA, ',' ) WITHIN GROUP ( ORDER BY ColumnB )
           AS test_sensor
  FROM   TableA
  GROUP BY ColumnC
)

Результаты

| COLUMNC | TEST_SENSOR1 | TEST_SENSOR2 | TEST_SENSOR3 | TEST_SENSOR4 |
|---------|--------------|--------------|--------------|--------------|
|  Z12345 |           20 |           30 |           40 |           50 |
...