【问题标题】:Oracle SQL - Pivot table rows to column and use sub query in pivotOracle SQL - 将表行数据透视表并在数据透视表中使用子查询
【发布时间】:2018-11-05 08:16:30
【问题描述】:

我正在开发 Oracle 12c R1 db,并有一个包含示例数据的示例视图,如下所示:
视图名称: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. 如何包含行总计
2. 如何包含列总计
3.如何包括预订酒店数量和
3. 是否可以在 PIVOT FOR HOTEL IN 子句中编写子查询。 (我尝试了子查询但出现错误)

我很感激这方面的任何帮助。

谢谢,
里查

【问题讨论】:

  • 哇太棒了.. 感谢 Barbaros Özhan、Gordon Linoff、Shrek 和 G.Arima。你们真棒。我无法想象一个问题有这么多种解决方案。
  • 非常感谢您提供的所有帮助以及您宝贵的时间。

标签: sql oracle pivot rollup


【解决方案1】:

只使用条件聚合:

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), () )

【讨论】:

  • 非常感谢@Gordon Linoff。你让复杂的问题看起来很简单。惊人的。我尝试了您的代码,但无法看到最后一行的标签“总计”。但一切都完美无缺。
  • @Richa 。 . .快速而肮脏的方法是使用SELECT COALESCE(customer, 'Grand Total') as customer, . . .
  • 太棒了。有效。出色的工作。再次感谢。我很感激。
  • 我正在尝试将返回的结果替换为 0 作为 null 或不带括号的破折号 (-)。在case语句中,我输入“”代替0。再次尝试用'-'代替0。由于整个case语句被SUM包围,SQL抛出错误。请问这方面有什么帮助吗?
  • 根据我的 OP 中显示的最终结果,如果值为 0 并且在“# Booked”列下,尝试将酒店结果显示为空白,并尝试将 0 替换为“-”
【解决方案2】:

可能有一个更简单的解决方案,但这应该可以帮助您入门 -

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

【讨论】:

  • 感谢您提供查询。如果我将另一家酒店添加为“Test Hyatt/Hilton”并将其包含在所有其他语句中,则会出现错误。我还尝试调试代码,只有“WITH”子句中的第一个查询执行没有错误,但其他派生查询抛出错误。 ORA-00904: "Test Hyatt/Hilton": 标识符无效
  • 可能是因为酒店名称中的 /。你可以尝试用 \ 转义它吗? ......就像在“Test Hyatt\/Hilton”中一样
【解决方案3】:

试试这个:

1) 包含行总数union 可以使用

2) 在第一个表 (p1) 中使用 sum 函数来包含列总计:与 sum 函数编写的代码相同

3) 要包含预订酒店的数量,another pivot 是必填项,即第二张表 (p2)


Step1:制作一张表 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 步:与客户和预订的酒店制作一张表 p2


create table p2 as
SELECT *  FROM
(
  SELECT customer,booked_status
  FROM cust
)
pivot 
 ( count(booked_status) 
  for booked_status in ('Booked' as Booked));

Step3:连接表p1和p2

Step4:对于行合计,取Step3中的表与汇总函数计算的行合计的并集


(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 |
+----------------+-------------+---------------+--------------+-------------+----------+

如果需要任何进一步的查询/解释,请告诉我。

【讨论】:

  • 感谢@G.Arima 的询问。我确实有基于不同表创建的视图。如果我为此创建新表,不确定数据是否会增长,我将不得不重新创建表。对不起,如果我的问题很愚蠢。
  • 我编写的解决方案是,即使您的数据增长,每个不同客户都会添加一行,仅此而已。 N 不必抱歉。乐于助人:)
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2019-07-22
  • 2011-06-18
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多