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
此致,
炖菜
我有一个 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
此致, 炖菜