如何在oracle 10g中将列转换为行

时间:2016-02-23 09:01:28

标签: sql oracle oracle10g pivot

假设我有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

如何编写查询?

2 个答案:

答案 0 :(得分:2)

使用 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"

答案 1 :(得分:1)

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