• 按月份进行统计


    在应用当中时常需要按照月份进行统计,比如整年的产量,一月的常量,二月的产量。。。十二月的常量。在表的设计的时候产量表一般有两个列,一个是时间,一个是产量。每月的产量对应表中的多条记录。一般产生的报表有如下格式:

    id Total Jan Feb Mar Apr May June July Aug Sep Oct Nov Dec
    id 12x x x x x x x x x x x x x

    下面对Nothwind数据库中的雇员2007年的销售情况按月进行统计。首先对这些数据进行感性认识下:

    SELECT empid, orderdate, unitprice, qty
    FROM Sales.Orders o JOIN Sales.OrderDetails od
    ON o.orderid = od.orderid
    WHERE DATEPART(YEAR, o.orderdate) = 2007
    ORDER BY empid, orderdate

    可以得到如下数据,我只拿empid = 1的数据:

    1 2007-01-01 00:00:00.000 99.00 21
    1 2007-01-01 00:00:00.000 14.40 35
    1 2007-01-01 00:00:00.000 16.00 30
      ……………    
    1 2007-02-21 00:00:00.000 10.20 15
    1 2007-02-21 00:00:00.000 12.00 25
      ……………    
    1 2007-03-05 00:00:00.000 3.6 25
      ……………    
      ……………    
      ……………    
    1 2007-12-11 00:00:00.000 39.00 33
      ……………    

    empid 为1 的每月在表中都有多条记录。下面采用两种方式去产生需要的报表。

    1)使用SUM聚合函数,因为sum参数可以是表达式,那么我使用case逻辑对sum聚合进行控制,比如对一月统计可以采用如下方式:

    	SUM(CASE DATEPART(MONTH, o.orderdate)
    			WHEN 1 THEN 1
    			ELSE 0
    		END * od.unitprice*od.qty) AS Jan
    采用如上方式,我只要在select list里面重复上面的聚合函数,就可以得到想要的报表。
    SELECT empid AS Empid,
    	SUM(od.unitprice * od.qty) AS Year,
    	SUM(CASE DATEPART(MONTH, o.orderdate)
    			WHEN 1 THEN 1
    			ELSE 0
    		END * od.unitprice*od.qty) AS Jan,
    	SUM(CASE DATEPART(MONTH, o.orderdate)
    			WHEN 2 THEN 1
    			ELSE 0
    		END * od.unitprice*od.qty) AS Feb,
    	SUM(CASE DATEPART(MONTH, o.orderdate)
    			WHEN 3 THEN 1
    			ELSE 0
    		END * od.unitprice*od.qty) AS Mar,
    	SUM(CASE DATEPART(MONTH, o.orderdate)
    			WHEN 4 THEN 1
    			ELSE 0
    		END * od.unitprice*od.qty) AS Apr,
    	SUM(CASE DATEPART(MONTH, o.orderdate)
    			WHEN 5 THEN 1
    			ELSE 0
    		END * od.unitprice*od.qty) AS May,
    	SUM(CASE DATEPART(MONTH, o.orderdate)
    			WHEN 6 THEN 1
    			ELSE 0
    		END * od.unitprice*od.qty) AS June,
    	SUM(CASE DATEPART(MONTH, o.orderdate)
    			WHEN 7 THEN 1
    			ELSE 0
    		END * od.unitprice*od.qty) AS July,
    	SUM(CASE DATEPART(MONTH, o.orderdate)
    			WHEN 8 THEN 1
    			ELSE 0
    		END * od.unitprice*od.qty) AS Aug,
    	SUM(CASE DATEPART(MONTH, o.orderdate)
    			WHEN 9 THEN 1
    			ELSE 0
    		END * od.unitprice*od.qty) AS Seo,
    	SUM(CASE DATEPART(MONTH, o.orderdate)
    			WHEN 10 THEN 1
    			ELSE 0
    		END * od.unitprice*od.qty) AS Oct,
    	SUM(CASE DATEPART(MONTH, o.orderdate)
    			WHEN 11 THEN 1
    			ELSE 0
    		END * od.unitprice*od.qty) AS Nov,
    	SUM(CASE DATEPART(MONTH, o.orderdate)
    			WHEN 12 THEN 1
    			ELSE 0
    		END * od.unitprice*od.qty) AS Dec	
    FROM Sales.Orders o JOIN Sales.OrderDetails od
    ON o.orderid = od.orderid
    WHERE DATEPART(YEAR, orderdate) = 2007
    GROUP BY empid
    ORDER by empid

    以上的方式逻辑比较清晰,但是list比较长,下面这种方式原理和上面一样,但是做法更巧妙。

    SELECT empid Empid, 
    	SUM(od.qty * od.unitprice) Year,
    	SUM(od.qty *od.unitprice * (1-ABS(SIGN(DATEPART(MONTH, o.orderdate) - 1)))) AS Jan,
    	SUM(od.qty *od.unitprice * (1-ABS(SIGN(DATEPART(MONTH, o.orderdate) - 2)))) AS Feb,
    	SUM(od.qty *od.unitprice * (1-ABS(SIGN(DATEPART(MONTH, o.orderdate) - 3)))) AS Mar,
    	SUM(od.qty *od.unitprice * (1-ABS(SIGN(DATEPART(MONTH, o.orderdate) - 4)))) AS Apr,
    	SUM(od.qty *od.unitprice * (1-ABS(SIGN(DATEPART(MONTH, o.orderdate) - 5)))) AS May,
    	SUM(od.qty *od.unitprice * (1-ABS(SIGN(DATEPART(MONTH, o.orderdate) - 6)))) AS June,
    	SUM(od.qty *od.unitprice * (1-ABS(SIGN(DATEPART(MONTH, o.orderdate) - 7)))) AS July,
    	SUM(od.qty *od.unitprice * (1-ABS(SIGN(DATEPART(MONTH, o.orderdate) - 8)))) AS Aug,
    	SUM(od.qty *od.unitprice * (1-ABS(SIGN(DATEPART(MONTH, o.orderdate) - 9)))) AS Sep,
    	SUM(od.qty *od.unitprice * (1-ABS(SIGN(DATEPART(MONTH, o.orderdate) - 10)))) AS Oct,
    	SUM(od.qty *od.unitprice * (1-ABS(SIGN(DATEPART(MONTH, o.orderdate) - 11)))) AS Nov,
    	SUM(od.qty *od.unitprice * (1-ABS(SIGN(DATEPART(MONTH, o.orderdate) - 12)))) AS Dec	
    FROM Sales.Orders o JOIN Sales.OrderDetails od
    ON o.orderid = od.orderid
    WHERE DATEPART(YEAR, orderdate) = 2007
    GROUP BY empid
    ORDER by empid

    注意上面sum函数的表达是,比如对于一月,有:

    od.qty *od.unitprice * (1-ABS(SIGN(DATEPART(MONTH, o.orderdate) - 1)))

    如果当前的记录是一月,那么DATEPART(MONTH, o.orderdate)是1, SIGN(DATEPART(MONTH, o.orderdate) – 1) = SIGN(1-1) =SIGN(0) = 0,

    od.qty*od.unitprice*(1-ABS(SIGN(DATEPART(MONTH, o.orderdate)-1))) = od.qty * od.unitprice*(1-ABS(0)) = od.qty * od.unitprice * 1

    如果当前的记录不是一月,那么DATEPART(MONTH, o.orderdate) >1, SIGN(DATEPART(MONTH, o.orderdate) – 1) = SIGN(>1) = 1,

    od.qty*od.unitprice*(1-ABS(SIGN(DATEPART(MONTH, o.orderdate)-1))) = od.qty * od.unitprice*(1-ABS(1)) = od.qty * od.unitprice * 0 = 0

    所以od.qty *od.unitprice * (1-ABS(SIGN(DATEPART(MONTH, o.orderdate) - 1)))计算一月的,

    SUM(od.qty *od.unitprice * (1-ABS(SIGN(DATEPART(MONTH, o.orderdate) - 2))))计算二月的。。。

    2)使用Pivot进行旋转。

    首先得到每个id每个月的销售量,如下:

    	SELECT empid, DATEPART(MONTH, o.orderdate) Month, unitprice * qty Total
    	FROM Sales.Orders o JOIN Sales.OrderDetails od
    	ON o.orderid = od.orderid
    	WHERE DATEPART(YEAR, o.orderdate) = 2007

    接下来对按Month列进行旋转,对Total列进行sum聚合计算:

    SELECT empid EmpId,
    	ISNULL(p.[1], 0) + ISNULL(p.[2],0) + ISNULL(p.[3], 0)+ISNULL(p.[4],0)+
    	ISNULL(p.[5], 0)+ISNULL(p.[6],0) + ISNULL(p.[7],0)+ISNULL(p.[8],0)+ISNULL(p.[9],0)+
    	ISNULL(p.[10],0)+ISNULL(p.[11],0)+ISNULL(p.[12],0) As Total,
    	P.[1] As Jan, P.[2] Feb, P.[3] AS Mar, P.[4] AS Apr,P.[5] May, P.[6] June, P.[7] July,
    	P.[8] Aug, P.[9] Sep, P.[10] Oct, P.[11] Nov, P.[12] Dec
    FROM
    (
    	SELECT empid, DATEPART(MONTH, o.orderdate) Month, unitprice * qty Total
    	FROM Sales.Orders o JOIN Sales.OrderDetails od
    	ON o.orderid = od.orderid
    	WHERE DATEPART(YEAR, o.orderdate) = 2007
    ) D1 PIVOT(
    	SUM(Total)
    	FOR Month IN ([1], [2], [3], [4], [5], [6], [7], [8], [9], [10], [11], [12])
    	) AS P
    ORDER BY empid

    注意如果表中存在某个employee某月没有销售记录,那么对应的结果null(不可以的),那么就需要ISNULL把null转成0,否则Total为null。

    那也可以先按empid,月份进行分组,然后在进行旋转,如下:

    SELECT  empid EmpId,
    	ISNULL(p.[1], 0) + ISNULL(p.[2],0) + ISNULL(p.[3], 0)+ISNULL(p.[4],0)+
    	ISNULL(p.[5], 0)+ISNULL(p.[6],0) + ISNULL(p.[7],0)+ISNULL(p.[8],0)+ISNULL(p.[9],0)+
    	ISNULL(p.[10],0)+ISNULL(p.[11],0)+ISNULL(p.[12],0) As Total,
    	P.[1] As Jan, P.[2] Feb, P.[3] AS Mar, P.[4] AS Apr,P.[5] May, P.[6] June, P.[7] July,
    	P.[8] Aug, P.[9] Sep, P.[10] Oct, P.[11] Nov, P.[12] Dec
    FROM (
    	SELECT empid,  DATEPART(MONTH, o.orderdate) month, SUM(od.unitprice * od.qty) total
    	FROM Sales.Orders o JOIN Sales.OrderDetails od
    	ON o.orderid = od.orderid
    	WHERE DATEPART(YEAR, o.orderdate) = 2007
    	GROUP BY empid,DATEPART(MONTH, o.orderdate)
    ) D1 PIVOT(
    	MAX(total)
    	FOR month IN ([1], [2], [3], [4], [5], [6], [7], [8], [9], [10], [11], [12])
    	) AS P
    ORDER BY empid

    以上一共采用四种不同的方式,两种不同的原理对数据进行统计。

  • 相关阅读:
    第二节:如何正确使用WebApi和使用过程中的一些坑
    nodejs中function*、yield和Promise的示例
    关于nodejs访问mysql的思考
    nodejs使用log4js记录日志
    nodejs初识
    Spring学习笔记(入门)
    mybatis使用注解开发
    MyBatis配置文件中的常用配置
    using 自动释放资源示例
    Java将byte[]和int的互相转换
  • 原文地址:https://www.cnblogs.com/fgynew/p/1669989.html
Copyright © 2020-2023  润新知