Oracle 数据透视表 - 一个 table 字段拆分为行和列

Oracle pivot - one table field split into rows and columns

我有一个 Oracle 12c table,看起来像这样:

Name     Class        Type 
--------------------------
Alice    Math           S
Alice    Female         A
Bob      Anthropology   S  
Bob      Male           A
Charlie  Science        S
Charlie  Tennis         A
Charlie  Male           A
Do       Math           S
Do       Female         A
Do       Tennis         A
Elmer    Male           A
Elmer    Science        S

我想调整 table 生成如下所示的报告。 Class 类型 "S" 是行,类型 "A" 是列。然后统计属于每一类的人数。例如,有两个人都是女性,并且都参加 class 数学 - Alice 和 Do.

              Female    Male    Tennis   Total
-----------------------------------------------
Math            2         0        1       3
Anthropology    0         1        0       1 
Science         0         2        1       3
Total           2         3        2       7

我熟悉 Oracle 中的数据透视表和多维数据集,但我无法在报表中的行和列之间拆分 Class 字段。

非常感谢您的帮助。

您可以使用如下条件聚合:

SQL> with dataa(name, class, type) as
  2  (
  3  select 'Alice',    'Math'           ,'S' from dual union all
  4  select 'Alice',    'Female'         ,'A' from dual union all
  5  select 'Bob',      'Anthropology'   ,'S' from dual union all
  6  select 'Bob',      'Male'           ,'A' from dual union all
  7  select 'Charlie',  'Science'        ,'S' from dual union all
  8  select 'Charlie',  'Tennis'         ,'A' from dual union all
  9  select 'Charlie',  'Male'           ,'A' from dual union all
 10  select 'Do',       'Math'           ,'S' from dual union all
 11  select 'Do',       'Female'         ,'A' from dual union all
 12  select 'Do',       'Tennis'         ,'A' from dual union all
 13  select 'Elmer',    'Male'           ,'A' from dual union all
 14  select 'Elmer',    'Science'        ,'S' from dual
 15  ),
 16  -- your query starts from here
 17  CTE AS
 18  (
 19  SELECT S.CLASS AS CLASS,
 20  COALESCE(SUM(CASE WHEN A.CLASS = 'Female' THEN 1 END),0) AS Female,
 21  COALESCE(SUM(CASE WHEN A.CLASS = 'Male' THEN 1 END),0) AS Male,
 22  COALESCE(SUM(CASE WHEN A.CLASS = 'Tennis' THEN 1 END),0) AS Tennis,
 23  COALESCE(SUM(CASE WHEN A.CLASS IN ('Female','Male','Tennis') THEN 1 END),0) AS TOTAL
 24  FROM DATAA S JOIN DATAA A  ON (A.name = S.name)
 25  WHERE S.type = 'S' AND A.TYPE = 'A'
 26  GROUP BY S.CLASS
 27  )
 28  SELECT CLASS, Female, Male, Tennis, TOTAL FROM CTE
 29  UNION ALL
 30  SELECT 'Total' AS CLASS, SUM(Female), SUM(Male), SUM(Tennis), SUM(TOTAL) FROM CTE;

CLASS            FEMALE       MALE     TENNIS      TOTAL
------------ ---------- ---------- ---------- ----------
Science               0          2          1          3
Anthropology          0          1          0          1
Math                  2          0          1          3
Total                 2          3          2          7

SQL>

干杯!!

目标 "row" 值和目标 "column" 值在不同的行中。为了执行 GROUP BY CUBE,您需要使用 JOIN 将它们放在同一输入行中。所以执行 JOIN,然后执行 GROUP BY CUBE,然后执行 PIVOT。为保持直白,请使用 GROUPING 函数查看何时对 "rows" 进行分组以及何时对 "columns" 进行分组。这会变成很多工作,并且您最终会在某些需要零的地方得到 NULL。出于好奇,这里是解决方案:

with data(name, class, type) as (
  select 'Alice',    'Math'           ,'S' from dual union all
  select 'Alice',    'Female'         ,'A' from dual union all
  select 'Bob',      'Anthropology'   ,'S' from dual union all
  select 'Bob',      'Male'           ,'A' from dual union all
  select 'Charlie',  'Science'        ,'S' from dual union all
  select 'Charlie',  'Tennis'         ,'A' from dual union all
  select 'Charlie',  'Male'           ,'A' from dual union all
  select 'Do',       'Math'           ,'S' from dual union all
  select 'Do',       'Female'         ,'A' from dual union all
  select 'Do',       'Tennis'         ,'A' from dual union all
  select 'Elmer',    'Male'           ,'A' from dual union all
  select 'Elmer',    'Science'        ,'S' from dual
)
, joined_data as (
  select s.class row_class, a.class col_class
  from data s
  join data a 
  on s.type = 'S' and a.type = 'A' and s.name = a.name
)
, cubed_data as (
  select case grouping(col_class) when 1 then 'Total' else col_class end col_class,
    row_class, grouping(row_class) gr_row, count(*) cnt
  from joined_data
  group by cube(row_class, col_class)
) 
select case gr_row when 1 then 'Total' else row_class end " ",
  "Female", "Male", "Tennis", "Total"
from cubed_data
pivot(  
  sum(cnt) for col_class in (
    'Female' as "Female",'Male' as "Male",'Tennis' as "Tennis",'Total' as "Total"
  )  
)  
order by gr_row, row_class;

                 Female       Male     Tennis      Total
------------ ---------- ---------- ---------- ----------
Anthropology                     1                     1
Math                  2                     1          3
Science                          2          1          3
Total                 2          3          2          7

此致, 炖菜

对于这个需求,我更喜欢Tejash的解决方案而不是我另一个答案中的PIVOT演示。但是,我建议使用 ROLLUP 而不是 UNION ALL。更改了两行并省略了 UNION ALL。

with data(name, class, type) as (
  select 'Alice',    'Math'           ,'S' from dual union all
  select 'Alice',    'Female'         ,'A' from dual union all
  select 'Bob',      'Anthropology'   ,'S' from dual union all
  select 'Bob',      'Male'           ,'A' from dual union all
  select 'Charlie',  'Science'        ,'S' from dual union all
  select 'Charlie',  'Tennis'         ,'A' from dual union all
  select 'Charlie',  'Male'           ,'A' from dual union all
  select 'Do',       'Math'           ,'S' from dual union all
  select 'Do',       'Female'         ,'A' from dual union all
  select 'Do',       'Tennis'         ,'A' from dual union all
  select 'Elmer',    'Male'           ,'A' from dual union all
  select 'Elmer',    'Science'        ,'S' from dual
)
SELECT case grouping(S.CLASS) when 1 then 'Total' else s.class end AS CLASS,
COALESCE(SUM(CASE WHEN A.CLASS = 'Female' THEN 1 END),0) AS Female,
COALESCE(SUM(CASE WHEN A.CLASS = 'Male' THEN 1 END),0) AS Male,
COALESCE(SUM(CASE WHEN A.CLASS = 'Tennis' THEN 1 END),0) AS Tennis,
count(*) AS TOTAL
FROM DATA S JOIN DATA A  ON (A.name = S.name)
WHERE S.type = 'S' AND A.TYPE = 'A'
GROUP BY rollup(S.CLASS);

CLASS            FEMALE       MALE     TENNIS      TOTAL
------------ ---------- ---------- ---------- ----------
Anthropology          0          1          0          1
Math                  2          0          1          3
Science               0          2          1          3
Total                 2          3          2          7

此致, 炖菜