oracle 10g如何将列转换为行
Posted
技术标签:
【中文标题】oracle 10g如何将列转换为行【英文标题】:How to convert column into rows in oracle 10g 【发布时间】:2016-02-23 09:01:27 【问题描述】:假设我有一个 Oracle sql 查询的结果:
Month Date
----- -----
Jan 10
Jan 15
Jan 20
Feb 11
Feb 16
Feb 25
我想以以下格式显示此数据:
Jan Jan Jan Feb Feb Feb
10 15 20 11 16 25
如何编写查询?
【问题讨论】:
看看PIVOT 列的标准是什么?每个月总会有 3 次约会吗?会一直是Jan
和Feb
还是其他月份?
Aleksej,在 PIVOT 中您必须使用聚合...但他需要保留所有值 =( 我不确定 PIVOT 在这种情况下是否有帮助
@SkyWalker 为什么不呢?不要分组,而是聚合,因此考虑所有值。
【参考方案1】:
使用 PIVOT:
SQL> WITH sample_data AS(
2 SELECT 'Jan' mnth, 10 dt FROM dual UNION ALL
3 SELECT 'Jan' mnth, 15 dt FROM dual UNION ALL
4 SELECT 'Jan' mnth, 20 dt FROM dual UNION ALL
5 SELECT 'Feb' mnth, 11 dt FROM dual UNION ALL
6 SELECT 'Feb' mnth, 16 dt FROM dual UNION ALL
7 SELECT 'Feb' mnth, 25 dt FROM dual
8 )
9 -- end of smaple_data mimicking real table
10 SELECT *
11 FROM
12 (SELECT dt, row_number() OVER(ORDER BY NULL) rn FROM sample_data
13 ) PIVOT (MAX(dt) FOR (rn)
14 IN (1 AS Jan_1, 2 AS jan_2, 3 AS Jan_3, 4 AS Feb_1, 5 Feb_2, 6 Feb_3));
JAN_1 JAN_2 JAN_3 FEB_1 FEB_2 FEB_3
---------- ---------- ---------- ---------- ---------- ----------
10 15 20 11 16 25
Under the hood PIVOT 与 MAX + CASE 相同。您可以在12c
中查看它,Oracle 将 EXPAND_SQL_TEXT 过程添加到 DBMS_UTILITY 包中。
SQL> VARIABLE c CLOB
SQL> BEGIN
2 dbms_utility.expand_sql_text(Q'[WITH sample_data AS(
3 SELECT 'Jan' mnth, 10 dt FROM dual UNION ALL
4 SELECT 'Jan' mnth, 15 dt FROM dual UNION ALL
5 SELECT 'Jan' mnth, 20 dt FROM dual UNION ALL
6 SELECT 'Feb' mnth, 11 dt FROM dual UNION ALL
7 SELECT 'Feb' mnth, 16 dt FROM dual UNION ALL
8 SELECT 'Feb' mnth, 25 dt FROM dual
9 )
10 -- end of smaple_data mimicking real table
11 SELECT *
12 FROM
13 (SELECT dt, row_number() OVER(ORDER BY NULL) rn FROM sample_data
14 ) PIVOT (MAX(dt) FOR (rn)
15 IN (1 AS Jan_1, 2 AS jan_2, 3 AS Jan_3, 4 AS Feb_1, 5 Feb_2, 6 Feb_3))]',:c);
16 END;
17 /
PL/SQL procedure successfully completed.
现在让我们看看 Oracle 在内部实际做了什么:
SQL> set long 100000
SQL> print c
C
--------------------------------------------------------------------------------
SELECT "A1"."JAN_1" "JAN_1",
"A1"."JAN_2" "JAN_2",
"A1"."JAN_3" "JAN_3",
"A1"."FEB_1" "FEB_1",
"A1"."FEB_2" "FEB_2",
"A1"."FEB_3" "FEB_3"
FROM
(SELECT MAX(
CASE WHE N ("A2"."RN"=1)
THEN "A2"."DT"
END ) "JAN_1",
MAX(
CASE
WHEN ("A2"."RN"=2)
THEN " A2"."DT"
END ) "JAN_2",
MAX(
CASE
WHEN ("A2"."RN"=3)
THEN "A2"."DT"
END ) "JAN_3" ,
MAX(
CASE
WHEN ("A2"."RN"=4)
THEN "A2"."DT"
END ) "FEB_1",
MAX(
CASE
WHEN ("A2". "RN"=5)
THEN "A2"."DT"
END ) "FEB_2",
MAX(
CASE
WHEN ("A2"."RN"=6)
THEN "A2"."DT"
END ) "FEB_3"
FROM
(SELECT "A3"."DT" "DT",
ROW_NUMBER() OVER ( ORDER BY NULL) " RN"
FROM (
(SELECT 'Jan' "MNTH",10 "DT" FROM "SYS"."DUAL" "A10"
)
UNION ALL (SE LECT 'Jan' "MNTH",15 "DT" FROM "SYS"."DUAL" "A9")
UNION ALL
(SELECT 'Jan' "MNTH",20 "DT" FROM "SYS"."DUAL" "A8"
)
UNION ALL
(SELECT 'Feb' "MNTH",11 "DT" FROM " SYS"."DUAL" "A7"
)
UNION ALL
(SELECT 'Feb' "MNTH",16 "DT" FROM "SYS"."DUAL" "A6"
)
UNION ALL
(SELECT 'Feb' "MNTH",25 "DT" FROM "SYS"."DUAL" "A5"
)) "A3"
) "A2"
) " A1"
【讨论】:
【参考方案2】:WITH dates( month, day ) AS (
SELECT 'Jan', 10 FROM DUAL UNION ALL
SELECT 'Jan', 15 FROM DUAL UNION ALL
SELECT 'Jan', 20 FROM DUAL UNION ALL
SELECT 'Feb', 11 FROM DUAL UNION ALL
SELECT 'Feb', 16 FROM DUAL UNION ALL
SELECT 'Feb', 25 FROM DUAL
),
ordered_dates( month, day, seq_no ) AS (
SELECT month,
day,
ROW_NUMBER() OVER ( PARTITION BY month ORDER BY day )
FROM dates
)
SELECT MAX( CASE WHEN month = 'Jan' AND seq_no = 1 THEN day END ) AS "Jan",
MAX( CASE WHEN month = 'Jan' AND seq_no = 2 THEN day END ) AS "Jan",
MAX( CASE WHEN month = 'Jan' AND seq_no = 3 THEN day END ) AS "Jan",
MAX( CASE WHEN month = 'Feb' AND seq_no = 1 THEN day END ) AS "Feb",
MAX( CASE WHEN month = 'Feb' AND seq_no = 2 THEN day END ) AS "Feb",
MAX( CASE WHEN month = 'Feb' AND seq_no = 3 THEN day END ) AS "Feb"
FROM ordered_dates;
输出:
Jan Jan Jan Feb Feb Feb
---------- ---------- ---------- ---------- ---------- ----------
10 15 20 11 16 25
【讨论】:
以上是关于oracle 10g如何将列转换为行的主要内容,如果未能解决你的问题,请参考以下文章