简体   繁体   English

SQL 查询按月分组并显示单个月总和记录

[英]SQL Query to group by month and display individual month sum for a record

I'm trying to sum product codes with a particular description as total products sold in a month over the years.我正在尝试将具有特定描述的产品代码汇总为多年来一个月内销售的总产品。

在此处输入图像描述

The two table used are:使用的两个表是:

CREATE TABLE product (
    prod_code          NUMBER(3) NOT NULL,
    prod_description   VARCHAR2(75) NOT NULL,
    prod_points        NUMBER(2) NOT NULL
);

CREATE TABLE product_sale (
    sale_no         NUMBER(8) NOT NULL,
    sale_datetime   DATE NOT NULL,
    sale_location   VARCHAR2(100) NOT NULL,
    prod_code       NUMBER(3) NOT NULL,
    officer_id     NUMBER(8) NOT NULL,
);

The date format is in 'DD-MON-YYYY HH12:MI PM'.日期格式为“DD-MON-YYYY HH12:MI PM”。

So far I'm able to formulate this:到目前为止,我能够制定这个:

select  
d.prod_description, 
extract(month from sale_datetime) as mon, 
count(d.prod_code) as count
from product d 
 join product_sale o on d.prod_code = o.prod_code
group by d.prod_description, extract(month from sale_datetime);
order by d.prod_code;

How do I separate the count as different month columns and get the sum of count in a separate column?如何将计数分隔为不同的月份列并在单独的列中获取计数总和?

I would just use conditional aggregation:我只会使用条件聚合:

select d.prod_description, count(*) as total,
       sum(case when extract(month from sale_datetime) = 1 then 1 else 0 end) as jan, 
       sum(case when extract(month from sale_datetime) = 2 then 1 else 0 end) as feb, 
       . . .
from product d join
     product_sale o 
     on d.prod_code = o.prod_code
group by d.prod_code, d.prod_description
order by d.prod_code;

Note that for the ordering, prod_code needs to be in the group by -- or you need to use an aggregation function such as order by min(d.prod_code) .请注意,对于排序, prod_code需要在group by -- 或者您需要使用聚合 function 例如order by min(d.prod_code)

If you want a separate row for totals, then use grouping sets :如果您想要单独的总计行,请使用grouping sets

group by grouping sets ( (d.prod_code, d.prod_description), () )

So the JAN column should contain the counts for January of every year.因此,JAN 列应包含每年一月的计数。

I will assume that in addition to the horizontal sum, you want a vertical sum.我将假设除了水平总和之外,您还需要垂直总和。

First you need to aggregate at different levels, then PIVOT to get the data from different rows into different columns of the same row.首先需要在不同级别进行聚合,然后PIVOT将不同行的数据获取到同一行的不同列中。

To aggregate at different levels, Oracle provides GROUP BY extensions such as CUBE :为了在不同级别进行聚合,Oracle 提供了GROUP BY扩展,例如CUBE

select prod_code, prod_description,
  nvl(extract(month from sale_datetime),0) mon,
  count(*) cnt
from product join product_sale using(prod_code)
group by cube((prod_code, prod_description), extract(month from sale_datetime))

Now you can pivot:现在你可以 pivot:

select * from (
  select prod_code, prod_description,
    nvl(extract(month from sale_datetime),0) mon,
    count(*) cnt
  from product join product_sale using(prod_code)
  group by cube((prod_code, prod_description), extract(month from sale_datetime))
)
pivot(max(cnt) for mon in(
  0 sum,1 jan,2 feb,3 mar,4 apr,5 may,6 jun,7 jul,8 aug,9 sep,10 oct,11 nov,12 dec
))
order by prod_description;

PROD_CODE   PROD_DESCRIPTION   SUM    JAN   FEB   MAR   APR   MAY   JUN   JUL   AUG   SEP   OCT   NOV   DEC 
        1   1                  516     61    57    62    60    62    30    31    31    30    31    30    31 
        2   2                  516     61    57    62    60    62    30    31    31    30    31    30    31 
        3   3                  516     61    57    62    60    62    30    31    31    30    31    30    31 
        4   4                  516     61    57    62    60    62    30    31    31    30    31    30    31 
        5   5                  516     61    57    62    60    62    30    31    31    30    31    30    31 
        6   6                  516     61    57    62    60    62    30    31    31    30    31    30    31 
        7   7                  516     61    57    62    60    62    30    31    31    30    31    30    31 
        8   8                  516     61    57    62    60    62    30    31    31    30    31    30    31 
        9   9                  516     61    57    62    60    62    30    31    31    30    31    30    31 
                              4644    549   513   558   540   558   270   279   279   270   279   270   279 

This is a simplified solution, for example I don't label the vertical sum row at the bottom.这是一个简化的解决方案,例如我没有 label 底部的垂直总和行。 For a complete solution and explanation of this technique, see https://stewashton.wordpress.com/2016/07/18/spreadsheet-like-totals-and-subtotals/有关此技术的完整解决方案和说明,请参阅https://stewashton.wordpress.com/2016/07/18/spreadsheet-like-totals-and-subtotals/

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM