Oracle SQL - 如何使用 PIVOT 进行计数

Posted

技术标签:

【中文标题】Oracle SQL - 如何使用 PIVOT 进行计数【英文标题】:Oracle SQL - how to count using PIVOT 【发布时间】:2020-09-24 09:01:43 【问题描述】:

我正在尝试使用 PIVOT 将一些行转换为列,但由于我需要在彼此之间使用多个计数,所以我被卡住了。

我只走到这一步:

SELECT * FROM 
(
    SELECT id, city, main_type, p_type 
    FROM table.table_name
)  sourcetable
PIVOT 
    (COUNT(id) FOR main_type IN ('Other', 'Private', 'Public')
)
ORDER BY city;

但是,对于每个 main_type,我有 1 到 4 个不同的 p_type 值,我想只计算每个城市一次。 这意味着对于每个 main_type,每个 p_type 都需要有 4 个“子计数”(因为没有更好的词)。这是上述查询后数据的样子:

|-------|-------|------|------|-------|
| City  |P_type |Other |Public|Private|
|-------|-------|------|------|-------|
|NYC    |Small  |  11  |   15 | 10    |
|-------|-------|------|------|-------|
|NYC    |Medium |  11  |   15 | 10    |
|-------|-------|------|------|-------|
|NYC    |Large  |  11  |   15 | 10    |
|-------|-------|------|------|-------|
|Dallas |Small  |  11  |   15 | 10    |
|-------|-------|------|------|-------|
|Dallas |Large  |  11  |   15 | 10    |
|-------|-------|------|------|-------|
|Miami  |Small  |  11  |   15 | 10    |
|-------|-------|------|------|-------|
|Miami  |Medium |  11  |   15 | 10    |
|-------|-------|------|------|-------|
|Miami  |Large  |  11  |   15 | 10    |
|-------|-------|------|------|-------|
|Miami  |XL     |  11  |   15 | 10    |
|-------|-------|------|------|-------|

I would like it to look like this:
|-------|------------|------------|-------------|------------|.......
| City  |Other/Small |Other/Small |Other/Medium |Public/Small|......
|-------|------------|------------|-------------|------------|
|NYC    |14          |  11        |   15        | 10         |
|-------|------------|------------|-------------|------------|
|Dallas |10          |  11        |   15        | 10         |
|-------|------------|------------|-------------|------------|
|Miami  |15          |  11        |   15        | 10         |
|-------|------------|------------|-------------|------------|

有没有办法在 SQL 中做到这一点?

附:我的 SQL 知识很初级,请多多包涵。

【问题讨论】:

【参考方案1】:

只使用条件聚合怎么样?

select City, P_type,
       sum(case when main_type = 'Other' then 1 else 0 end) as other,
       sum(case when main_type = 'Public' then 1 else 0 end) as Public,
       sum(case when main_type = 'Private' then 1 else 0 end) as Private
from table.table_name
where city, p_type
group by City, P_Type;

编辑:

您可以像这样添加更多列:

select City,
       sum(case when p_type = 'Small' and main_type = 'Other' then 1 else 0 end) as small_other,
       sum(case when p_type = 'Small' and main_type = 'Public' then 1 else 0 end) as small_Public,
       sum(case when p_type = 'Small' and main_type = 'Private' then 1 else 0 end) as small_Private,
       sum(case when p_type = 'Medium' and main_type = 'Other' then 1 else 0 end) as medium_other,
       . . . 
from table.table_name
where city, p_type
group by City;

【讨论】:

仅此一项并不能帮助我计算一次所有城市。对于每个 main_type,我需要计算每个 p_type 的值,例如。对于 NYC 分别计算 Public 和 Small、Public 和 Medium 等,直到我用尽所有值。这有意义吗? @AnnaB 。 . .您在问题中有一个看起来像您想要的结果的表格您在问题中没有表格来显示跨列旋转的所有值,所以我认为这个问题不清楚。无论如何,我编辑了答案以向您展示如何概括为拥有更多列。 @Gordon...我发布的表格是使用数据透视后的结果。我已经编辑了我的初始帖子以使其清楚。您的编辑很有帮助。我相信我现在得到了想要的结果,而且它是一些 Sql,它不超出我的水平:D。【参考方案2】:

有一些静态透视方法,例如使用PIVOT 子句或Conditional Aggregation,其中所有生成的透视列都应显式指定,而没有直接的动态方法通过使用SQL仅限。

SYS_REFCURSOR 在存储函数中(例如,PL/SQL 使用而不是直接使用 SQL)可以用作替代方法以获得动态生成的结果集(例如。动态枢轴):

CREATE OR REPLACE FUNCTION Get_Cities_RS RETURN SYS_REFCURSOR IS
  v_recordset SYS_REFCURSOR;
  v_sql       VARCHAR2(32767);
  v_str       VARCHAR2(32767);
BEGIN
  SELECT LISTAGG( ''''||main_type||''' AS "'||LOWER(main_type)||'"' , ',' ) 
                 WITHIN GROUP ( ORDER BY 1 ) --# "ORDER BY" clause is required
    INTO v_str
    FROM ( SELECT DISTINCT main_type  
             FROM cities ); 

  v_sql :=
  'SELECT *
     FROM (
           SELECT id, city, main_type, p_type 
             FROM cities
          )
    PIVOT
    (
     COUNT(id) FOR main_type IN ( '|| v_str ||' )
    )
    ORDER BY city';

  OPEN v_recordset FOR v_sql;
  RETURN v_recordset;
END;
/

然后运行以下代码:

VAR rc REFCURSOR
EXEC :rc := Get_Cities_RS;
PRINT rc

从 SQL Developer 的命令行查看预期的结果集。

Demo

【讨论】:

以上是关于Oracle SQL - 如何使用 PIVOT 进行计数的主要内容,如果未能解决你的问题,请参考以下文章

ORACLE SQL:如何在 Pivot 函数中将 NULL 替换为 0

在 Oracle SQL 中按报告日期的 PIVOT 值

Oracle SQL - 在 PIVOT 之前更新值

Oracle sql 中的 PIVOT

Oracle SQL group by 查询,一种 PIVOT [重复]

Oracle SQL Pivot -- 获取行总计