Oracle SQL - 将 table 行转置为列并在转置中使用子查询
Oracle SQL - Pivot table rows to column and use sub query in pivot
我正在使用 Oracle 12c R1 数据库,并且有一个包含示例数据的示例视图,如下所示:
视图名称:CUST_HOTEL_VIEW
+----------------+---------------+---------------+
| Customer | Hotel | Booked Status |
+----------------+---------------+---------------+
| John Smith | Beverly Hills | Booked |
| John Smith | Royal Palms | |
| Marilyn Lawson | Beverly Hills | |
| John Smith | Ritz-Carlton | |
| Marilyn Lawson | Royal Palms | |
| Sarah Elliot | Royal Palms | |
| Sarah Elliot | Ritz-Carlton | Booked |
| Sarah Elliot | Royal Palms | Booked |
+----------------+---------------+---------------+
根据上面的数据,我试图通过行总计、列总计和每个客户预订的酒店数量获得低于数据透视表的输出:
+----------------+-------------+---------------+--------------+-------------+----------+
| Customer | Royal Palms | Beverly Hills | Ritz-Carlton | Grand Total | # Booked |
+----------------+-------------+---------------+--------------+-------------+----------+
| John Smith | 1 | 1 | 1 | 3 | 1 |
| Marilyn Lawson | 1 | 1 | | 2 | - |
| Sarah Elliot | 2 | | 1 | 3 | 2 |
| Grand Total | 4 | 2 | 2 | 8 | 3 |
+----------------+-------------+---------------+--------------+-------------+----------+
我尝试了以下查询来生成数据透视表
SELECT * FROM
(
SELECT CUSTOMER, HOTEL
FROM CUST_HOTEL_VIEW
)
PIVOT
(
COUNT(HOTEL)
FOR HOTEL IN ('Royal Palms' as "Royal Palms",'Beverly Hills' as "Beverly Hills",'Ritz-Carlton' as "Ritz-Carlton")
)
ORDER BY CUSTOMER
我想知道:
1.如何包含Row Grand Total
2.如何包含Column Grand Total
3.如何包括预订酒店数量和
3. 是否可以在 PIVOT FOR HOTEL IN 子句中编写子查询。 (我尝试了子查询但出现错误)
我很感激这方面的任何帮助。
谢谢,
里查
可能有更简单的解决方案,但这应该可以帮助您入门 -
WITH A AS (
SELECT
*
FROM
(
SELECT
CUSTOMER,
HOTEL,
BOOKED_STATUS
FROM
TABLE1
)
PIVOT ( COUNT ( HOTEL )
FOR HOTEL
IN ( 'ROYAL PALMS' AS "ROYAL PALMS",'BEVERLY HILLS' AS "BEVERLY HILLS",'RITZ-CARLTON' AS "RITZ-CARLTON" )
)
),B AS (
SELECT
CUSTOMER,
"ROYAL PALMS",
"BEVERLY HILLS",
"RITZ-CARLTON",
SUM("ROYAL PALMS" + "BEVERLY HILLS" + "RITZ-CARLTON") AS "GRAND TOTAL"
FROM
A
GROUP BY
CUSTOMER,
"ROYAL PALMS",
"BEVERLY HILLS",
"RITZ-CARLTON"
),C AS (
SELECT
CUSTOMER,
SUM("ROYAL PALMS" + "BEVERLY HILLS" + "RITZ-CARLTON") AS NBOOK
FROM
A
WHERE
BOOKED_STATUS IS NOT NULL
GROUP BY
CUSTOMER
),D AS (
SELECT
B.CUSTOMER,
SUM("ROYAL PALMS") AS "ROYAL PALMS",
SUM("BEVERLY HILLS") AS "BEVERLY HILLS",
SUM("RITZ-CARLTON") AS "RITZ-CARLTON",
SUM("GRAND TOTAL") AS "GRAND TOTAL",
NVL(C.NBOOK,0) AS NBOOK
FROM
B,
C
WHERE
B.CUSTOMER = C.CUSTOMER (+)
GROUP BY
B.CUSTOMER,
NVL(C.NBOOK,0)
) SELECT
*
FROM
D
UNION
SELECT
'GRAND TOTAL' AS CUSTOMER,
SUM("ROYAL PALMS"),
SUM("BEVERLY HILLS"),
SUM("RITZ-CARLTON"),
SUM("GRAND TOTAL") AS "GRAND TOTAL",
SUM(NBOOK) AS NBOOK
FROM
D
ORDER BY 5,1;
输出 -
"CUSTOMER","ROYAL PALMS","BEVERLY HILLS","RITZ-CARLTON","GRAND TOTAL","NBOOK"
"MARILYN LAWSON",1,1,0,2,0
"JOHN SMITH",1,1,1,3,1
"SARAH ELLIOT",2,0,1,3,2
"GRAND TOTAL",4,2,2,8,3
试试这个:
1) 要包括行总数 union
可以使用
2) 包含列总计 sum
函数在第一个 table (p1) 中使用:您使用求和函数编写的相同代码
3) 要包含预订的酒店数量,需要 another pivot
,即第二个 table (p2)
第 1 步:与客户、不同酒店及其总计(总列)
进行了 table p1
create table p1 as
SELECT customer,RoyalPalms,BeverlyHills,RitzCarlton,sum(RoyalPalms + BeverlyHills + RitzCarlton) as GrandTotal FROM
(
SELECT CUSTOMER, HOTEL
FROM CUST
)
PIVOT
( COUNT(HOTEL)
FOR HOTEL IN ('Royal Palms' as RoyalPalms,'Beverly Hills' as BeverlyHills,
'Ritz-Carlton' as RitzCarlton) )
group by customer,RoyalPalms,BeverlyHills,RitzCarlton
order by customer;
第 2 步:与客户和预订的酒店进行 table p2
create table p2 as
SELECT * FROM
(
SELECT customer,booked_status
FROM cust
)
pivot
( count(booked_status)
for booked_status in ('Booked' as Booked));
第三步:加入table p1和p2
Step4:对于行总计,将Step3中的table与汇总函数
计算出的行总计并集
(SELECT a.*,b.booked
from p1 a
left join
p2 b
on a.customer = b.customer)
union all
SELECT 'GrandTotal', Sum(RoyalPalms),sum(BeverlyHills),sum(RitzCarlton),
sum(GrandTotal),sum(booked) From test;
输出:
+----------------+-------------+---------------+--------------+-------------+----------+
| Customer | Royal Palms | Beverly Hills | Ritz-Carlton | Grand Total | # Booked |
+----------------+-------------+---------------+--------------+-------------+----------+
| John Smith | 1 | 1 | 1 | 3 | 1 |
| Marilyn Lawson | 1 | 1 | | 2 | - |
| Sarah Elliot | 2 | | 1 | 3 | 2 |
| Grand Total | 4 | 2 | 2 | 8 | 3 |
+----------------+-------------+---------------+--------------+-------------+----------+
如果需要进一步 queries/explanation,请告诉我。
只使用条件聚合:
SELECT COALESCE(customer, 'Grand Total') as customer,
SUM(CASE WHEN Hotel = 'Royal Palms' THEN 1 ELSE 0 END) as "Royal Palms",
SUM(CASE WHEN Hotel = 'Beverly Hills' THEN 1 ELSE 0 END) as "Beverly Hills",
SUM(CASE WHEN Hotel = 'Ritz-Carlton' THEN 1 ELSE 0 END) as "Ritz-Carlton" ,
COUNT(*) as "Grand Total",
COUNT(Booked_Status) as "Num Booked"
FROM CUST_HOTEL_VIEW
GROUP BY ROLLUP(CUSTOMER)
ORDER BY CUSTOMER;
条件聚合比 pivot
灵活得多。就我个人而言,我认为 pivot
语法没有任何理由:它在一件事上做得很好,但不像传统的 SQL 语句那样是构建块。
ROLLUP()
也很有帮助。您还可以使用:
GROUP BY GROUPING SETS ( (CUSTOMER), () )
我正在使用 Oracle 12c R1 数据库,并且有一个包含示例数据的示例视图,如下所示:
视图名称:CUST_HOTEL_VIEW
+----------------+---------------+---------------+
| Customer | Hotel | Booked Status |
+----------------+---------------+---------------+
| John Smith | Beverly Hills | Booked |
| John Smith | Royal Palms | |
| Marilyn Lawson | Beverly Hills | |
| John Smith | Ritz-Carlton | |
| Marilyn Lawson | Royal Palms | |
| Sarah Elliot | Royal Palms | |
| Sarah Elliot | Ritz-Carlton | Booked |
| Sarah Elliot | Royal Palms | Booked |
+----------------+---------------+---------------+
根据上面的数据,我试图通过行总计、列总计和每个客户预订的酒店数量获得低于数据透视表的输出:
+----------------+-------------+---------------+--------------+-------------+----------+
| Customer | Royal Palms | Beverly Hills | Ritz-Carlton | Grand Total | # Booked |
+----------------+-------------+---------------+--------------+-------------+----------+
| John Smith | 1 | 1 | 1 | 3 | 1 |
| Marilyn Lawson | 1 | 1 | | 2 | - |
| Sarah Elliot | 2 | | 1 | 3 | 2 |
| Grand Total | 4 | 2 | 2 | 8 | 3 |
+----------------+-------------+---------------+--------------+-------------+----------+
我尝试了以下查询来生成数据透视表
SELECT * FROM
(
SELECT CUSTOMER, HOTEL
FROM CUST_HOTEL_VIEW
)
PIVOT
(
COUNT(HOTEL)
FOR HOTEL IN ('Royal Palms' as "Royal Palms",'Beverly Hills' as "Beverly Hills",'Ritz-Carlton' as "Ritz-Carlton")
)
ORDER BY CUSTOMER
我想知道:
1.如何包含Row Grand Total
2.如何包含Column Grand Total
3.如何包括预订酒店数量和
3. 是否可以在 PIVOT FOR HOTEL IN 子句中编写子查询。 (我尝试了子查询但出现错误)
我很感激这方面的任何帮助。
谢谢,
里查
可能有更简单的解决方案,但这应该可以帮助您入门 -
WITH A AS (
SELECT
*
FROM
(
SELECT
CUSTOMER,
HOTEL,
BOOKED_STATUS
FROM
TABLE1
)
PIVOT ( COUNT ( HOTEL )
FOR HOTEL
IN ( 'ROYAL PALMS' AS "ROYAL PALMS",'BEVERLY HILLS' AS "BEVERLY HILLS",'RITZ-CARLTON' AS "RITZ-CARLTON" )
)
),B AS (
SELECT
CUSTOMER,
"ROYAL PALMS",
"BEVERLY HILLS",
"RITZ-CARLTON",
SUM("ROYAL PALMS" + "BEVERLY HILLS" + "RITZ-CARLTON") AS "GRAND TOTAL"
FROM
A
GROUP BY
CUSTOMER,
"ROYAL PALMS",
"BEVERLY HILLS",
"RITZ-CARLTON"
),C AS (
SELECT
CUSTOMER,
SUM("ROYAL PALMS" + "BEVERLY HILLS" + "RITZ-CARLTON") AS NBOOK
FROM
A
WHERE
BOOKED_STATUS IS NOT NULL
GROUP BY
CUSTOMER
),D AS (
SELECT
B.CUSTOMER,
SUM("ROYAL PALMS") AS "ROYAL PALMS",
SUM("BEVERLY HILLS") AS "BEVERLY HILLS",
SUM("RITZ-CARLTON") AS "RITZ-CARLTON",
SUM("GRAND TOTAL") AS "GRAND TOTAL",
NVL(C.NBOOK,0) AS NBOOK
FROM
B,
C
WHERE
B.CUSTOMER = C.CUSTOMER (+)
GROUP BY
B.CUSTOMER,
NVL(C.NBOOK,0)
) SELECT
*
FROM
D
UNION
SELECT
'GRAND TOTAL' AS CUSTOMER,
SUM("ROYAL PALMS"),
SUM("BEVERLY HILLS"),
SUM("RITZ-CARLTON"),
SUM("GRAND TOTAL") AS "GRAND TOTAL",
SUM(NBOOK) AS NBOOK
FROM
D
ORDER BY 5,1;
输出 -
"CUSTOMER","ROYAL PALMS","BEVERLY HILLS","RITZ-CARLTON","GRAND TOTAL","NBOOK"
"MARILYN LAWSON",1,1,0,2,0
"JOHN SMITH",1,1,1,3,1
"SARAH ELLIOT",2,0,1,3,2
"GRAND TOTAL",4,2,2,8,3
试试这个:
1) 要包括行总数 union
可以使用
2) 包含列总计 sum
函数在第一个 table (p1) 中使用:您使用求和函数编写的相同代码
3) 要包含预订的酒店数量,需要 another pivot
,即第二个 table (p2)
第 1 步:与客户、不同酒店及其总计(总列)
进行了 table p1create table p1 as
SELECT customer,RoyalPalms,BeverlyHills,RitzCarlton,sum(RoyalPalms + BeverlyHills + RitzCarlton) as GrandTotal FROM
(
SELECT CUSTOMER, HOTEL
FROM CUST
)
PIVOT
( COUNT(HOTEL)
FOR HOTEL IN ('Royal Palms' as RoyalPalms,'Beverly Hills' as BeverlyHills,
'Ritz-Carlton' as RitzCarlton) )
group by customer,RoyalPalms,BeverlyHills,RitzCarlton
order by customer;
第 2 步:与客户和预订的酒店进行 table p2
create table p2 as
SELECT * FROM
(
SELECT customer,booked_status
FROM cust
)
pivot
( count(booked_status)
for booked_status in ('Booked' as Booked));
第三步:加入table p1和p2
Step4:对于行总计,将Step3中的table与汇总函数
计算出的行总计并集(SELECT a.*,b.booked
from p1 a
left join
p2 b
on a.customer = b.customer)
union all
SELECT 'GrandTotal', Sum(RoyalPalms),sum(BeverlyHills),sum(RitzCarlton),
sum(GrandTotal),sum(booked) From test;
输出:
+----------------+-------------+---------------+--------------+-------------+----------+
| Customer | Royal Palms | Beverly Hills | Ritz-Carlton | Grand Total | # Booked |
+----------------+-------------+---------------+--------------+-------------+----------+
| John Smith | 1 | 1 | 1 | 3 | 1 |
| Marilyn Lawson | 1 | 1 | | 2 | - |
| Sarah Elliot | 2 | | 1 | 3 | 2 |
| Grand Total | 4 | 2 | 2 | 8 | 3 |
+----------------+-------------+---------------+--------------+-------------+----------+
如果需要进一步 queries/explanation,请告诉我。
只使用条件聚合:
SELECT COALESCE(customer, 'Grand Total') as customer,
SUM(CASE WHEN Hotel = 'Royal Palms' THEN 1 ELSE 0 END) as "Royal Palms",
SUM(CASE WHEN Hotel = 'Beverly Hills' THEN 1 ELSE 0 END) as "Beverly Hills",
SUM(CASE WHEN Hotel = 'Ritz-Carlton' THEN 1 ELSE 0 END) as "Ritz-Carlton" ,
COUNT(*) as "Grand Total",
COUNT(Booked_Status) as "Num Booked"
FROM CUST_HOTEL_VIEW
GROUP BY ROLLUP(CUSTOMER)
ORDER BY CUSTOMER;
条件聚合比 pivot
灵活得多。就我个人而言,我认为 pivot
语法没有任何理由:它在一件事上做得很好,但不像传统的 SQL 语句那样是构建块。
ROLLUP()
也很有帮助。您还可以使用:
GROUP BY GROUPING SETS ( (CUSTOMER), () )