在Oracle中将一列数据拆分为多个列

时间:2018-05-08 10:53:35

标签: sql oracle pivot

在我的oracle查询中,我使用如下方法检索记录,结果如下所示 -

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 :(得分:0)

您可以使用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
) )

<强> Results

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

<强> Results

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

答案 1 :(得分:0)

如果你选择LISTAGG,LISTAGG有一个警告,它会忽略NULL值。你确定你的columnA总是有数据吗?例如,如果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,保持test_sensor2的NULL值,其余值保持在适当的位置。

然而,现在还有另一个问题,即'[^,]+'形式的正则表达式会导致同样的问题!因此,即使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;