在Sqlserver下巧用行列转换日期的数据统计
原文:在Sqlserver下巧用行列转换日期的数据统计

在Sqlserver下巧用行列转换日期的数据统计

前言

在SQLSERVER 中有很多统计函数的基础语法,有使用Group By 或 partition by 后配合Sum,Count(*) 等用法。常应用于统计网站的PV流量、合同项目中月收入等业务场景中。在文中我分享下最近做过的统计小案例,和大家互相学习下:)

背景

合同中行项目按月收入的统计

1.业务逻辑及需求 

1.1 表业务逻辑

合同是公司间互相签署的法律契约,一份合同从诞生起,就开始流转于公司的各个部门,最核心的还是盈亏的数值。盈亏是结果,数据的产生源于每个自然月或其他时段的汇总。 往往在实际业务中,例如有些广告行业,立项是分为固定排期和合同活动收入。

固定排期一般以一个自然月为周期,例如[201503,201504]间产生的预收入;活动收入表中的活动是指收入周期不固定,可能ConfirmDate  发生在一个月中的若干天中,也可能在间隔一个月后发生。

无论是固定排期还是活动收入都和行项目有关,行项目是一个编号,一个行项目可以对应多次排期或活动收入的统计,在我给大家介绍的Demo中,将暂时考虑固定排期的情况。

1.2 项目的需求

统计合同中行项目的金额:分为结转金额数据汇总,和按自然月条件下金额的汇总。

2.准备的基础表

2.1 合同信息表

CREATE TABLE  ContractInfo --基本信息表
(
[ContractCode] [varchar](50) Primary key
,[CustomName] [varchar](100) NULL,
)insert into ContractInfo
(ContractCode,CustomName)
values('30100013000861','弘化四方'),('30100013000862','明心见性'),('30100013000863','心绽莲花')

2.2 合同行项目表

CREATE TABLE ContractLine --合同行项目表
([LineID] [int] IDENTITY(1,1) Primary Key NOT NULL,[ContractCode] [varchar](50) NOT NULL,
)insert into ContractLine
(ContractCode)
values('30100013000861'),('30100013000862'),('30100013000862') ,('30100013000863'),('30100013000863') 

2.3 合同固定排期表

CREATE TABLE ContractSchedule  --合同固定排期表([ScheduleID] [int]  Primary key  NOT NULL,-- 排期ID[LineID] [int] NOT NULL, -- 行项目ID[Period] [int] NOT NULL, --时间段[Amount] [decimal](18, 2) NOT NULL, --交易金额
)insert into ContractSchedule
(ScheduleID,LineID,Period,Amount)
values
(89106,1,201507,90900.00)
,(89107,1,201508,9453.00)
,(89108,1,201510,13000.00)
,(89109,2,201501,12000.00)
,(89110,2,201503,11000.00)
,(89111,3,201509,9000.00)
,(89112,4,201510,8500.00)

3.补充其他(待)

基础知识点

1.FOR XML PATH  //用于统计时转换行列的格式,

参考:王波洋老师的 灵活运用 FOR XML PATH

2.PIVOT (SUM(Amount)) For Period //用于基础表基础上的行列转换,

参考:大志若愚老师的 纵表、横表互转的SQL

3.Select SUM(Amount) From ContractSchedule

group by LineID // 根据条件汇总数据

实现思路

逻辑 

/*计算时间的基础序列*/ ->/*格式化日期序列*/ -> /*关联逻辑表,查询计算8月份之前的汇总,8月份之后的按月份统计*/

代码片段

 1 /*---------------计算时间的基础序列------------*/
 2
 3 /*获取日期序列起始值*/DECLARE @sdate CHAR(10);     DECLARE @edate CHAR(10);
 4  SET @sdate = '2015-08-01'--开始日期
 5  SET @edate = '2015-12-1'
 6
 7  /*存入临时表*/
 8   SELECT * into #DateArr
 9   from (
10      select
11      CONVERT(varchar(6),DATEADD(MONTH,a.number,@sdate),112)             totalDate
12      FROM master..spt_values a --系统表
13      WHERE a.type = 'P'
14      AND number BETWEEN 0 AND (select DATEDIFF(MONTH,@sdate,@edate))
15 )a
16
17 select * from #DateArr

1 /*格式化日期序列,用@Months接收*/
2       DECLARE @Months VARCHAR(1000);
3       DECLARE @SQL NVARCHAR(MAX);
4
5     SET @SQL = 'SELECT @Months=STUFF((SELECT DISTINCT '',[''+totalDate+'']'' FROM #DateArr s
6     FOR XML PATH('''')),1,1,'''')';
7     EXECUTE sp_executesql @SQL,N'@Months VARCHAR(1000) OUTPUT',@Months OUTPUT;
8
9    print @Months    

 1 /*未关联时间序列前的基础数据*/
 2 with tab as(
 3 select
 4        c.ContractCode
 5        ,c.CustomName
 6        ,cl.LineID
 7        ,ISNULL(b.TheEndYearAmount,0) as NearAYearAgo
 8        ,cs.Amount
 9        ,cs.Period
10         from ContractInfo c
11     left join
12     ContractLine cl
13     on c.ContractCode=cl.ContractCode
14     left join
15     ContractSchedule cs
16     on cs.LineID=cl.LineID
17             --计算8月份之前的统计
18         left join
19         (
20          select LineID,Sum(Amount) as TheEndYearAmount
21          from
22          ContractSchedule
23          where Period between 201508 and 201512
24          group by LineID
25           --select * from ContractSchedule
26         )b on b.LineID=cl.LineID
27  ) select * from tab

 1 /*--------添加日期序列后的统计 --------*/
 2 SET @SQL='
 3 with tab as(
 4 select c.CustomName
 5        ,ISNULL(b.TheEndYearAmount,0) as NearAYearAgo
 6        ,c.ContractCode  --合同号
 7        ,cl.LineID  --合同的行ID
 8        ,cs.Amount  --待计算的数量
 9        ,cs.Period  --统计的日期
10         from ContractInfo c
11     left join
12     ContractLine cl
13     on c.ContractCode=cl.ContractCode
14     left join
15     ContractSchedule cs
16     on cs.LineID=cl.LineID
17             --计算8月份之前的统计
18         left join
19         (
20          select LineID,Sum(Amount) as TheEndYearAmount
21          from
22          ContractSchedule
23          where Period between 201412 and 201508
24          group by LineID
25           --select * from ContractSchedule
26         )b on b.LineID=cl.LineID
27  ) select * from tab
28  PIVOT (SUM(Amount) FOR Period
29  IN(
30    '+@Months+'
31  ))b
32  '
33 EXEC (@SQL)

查询后结果   脚本下载

思考

留下的思考

1. 对空值的处理: select * from tab PIVOT (SUM(Amount)...

这里我尝试用ISNULL(SUM(Amount),0.00) 去处理,但语法没有通过,我将继续尝试..

2. 脚本片段中获取日期序列,或许在其他统计脚本中也会复用,我准备写到标量函数或表值函数中试一下。

3. 常用的业务统计脚本中关联的表比较多,如何能有效避免重复,在最后结果集中减少使用 distinct ,而使用Group by 去过滤重复字段

这一个知识点我比较薄弱,不断总结,在分享经验给大家,少走弯路。

感谢

我的好朋友欢,一直致力于SQL方面的统计,他给了我很多建议{

1.理解需求并开始写之前,要知道每个表里会出现什么数据

2.出现问题后,先查表与表之间是什么关联,关联从少到多,去检查错误

3.最核心的想清楚再写sql,如果脑子里不清楚就上手写,万一出现一个错误的想法,再纠正就麻烦了 

}

博学的龙叔,总是第一时间帮助大家理清混乱的逻辑。

永远的涛哥,在不断修改涛哥的统计脚本中,使自己受益匪浅。

posted on 2015-03-31 10:06 NET未来之路 阅读(...) 评论(...) 编辑 收藏

转载于:https://www.cnblogs.com/lonelyxmas/p/4380084.html

在Sqlserver下巧用行列转换日期的数据统计相关推荐

  1. MySQL中实现连续日期内数据统计,缺省天数0补全

    某一日,需要查询订单表中一个月每天的金额数 查询出数据如下: array(14) {[0] => array(2) {["money"] => string(7) &q ...

  2. SELECT行列转换

    原文地址:http://www.2cto.com/database/201108/100792.html SELECT行列转换 前几天有一个群友在群里面(190359237)有问到列转换成行的问题,今 ...

  3. SQL-SERVER 中使用POVIT完成行列转换

    假如现在我们有这样一张表,命名为TB_STUDENT_SCORE 表中内容为: 可能会用到pivot的常见情况是:需要生成交叉表格报表以汇总数据.例如,假设需要在 TB_STUDENT_SCORE表中 ...

  4. sqlserver行列转换

    一.使用sum(case when) 废话不多说,直接上图 select projectDeclare_id,             sum(case when seq=0 then score1 ...

  5. SQL Server 行列转换(2)

    参考前一个例子http://www.cnblogs.com/insus/articles/1969896.html,现想使用另外一种方式来处理行列转换,实现下面效果: 参考代码: View Code ...

  6. SQL Server 行列转换(1)

    参考前一个SQL的行列转换例子http://www.cnblogs.com/insus/articles/1969896.html ,觉得不够自由,需要去预先知道记录的内容去定义行或列. 下面这个方法 ...

  7. Hive-day06基本函数_窗口函数_行列转换_UDF_连续登录问题

    hive-基本函数_窗口函数_行列转换_UDF_连续登录问题 目录 hive-基本函数_窗口函数_行列转换_UDF_连续登录问题 SQL练习 hive语句的执行顺序 from-->join--& ...

  8. [转载]SQL Server行列转换实现

    一.Pivot和UnPivot介绍 1.Pivot介绍 PIVOT用于将列值旋转为列名(即行转列),在SQL Server 2000可以用聚合函数配合CASE语句实现 PIVOT的一般语法是:PIVO ...

  9. Sql2008的行列转换之行转列

    今天在工作的时候遇到了行列转换的问题,记得去年有一段时间经常写,但是许久不用已经记不太得了.好记性不如烂笔头,忙完之后赶紧记录一下. 关键字:PIVOT(行转列),UNPIVOT(列转行) 先说说 P ...

最新文章

  1. ASP.NET3种验证码[转]
  2. 内核中修改和保存defconfig的方法
  3. weblogic连接池不释放问题解决_数据库连接池引起的FullGC问题,看我如何一步步排查、分析、解决...
  4. 开发发布npm module包
  5. 基于OIDC(OpenID Connect)的SSO
  6. Pycharm安装第三方库
  7. mcq 队列_基于人工智能的智能体能力倾向问答(MCQ) 套装1
  8. Docker配置国内镜像加速
  9. App性能测试-GT
  10. python二级基础题,计算机二级python部分基础操作题
  11. Ubantu 安装ftp 之诡异
  12. canvas画圆形图片
  13. Flink:flink问题总结
  14. android 在线获取音乐歌词lrc文件
  15. Educational Codeforces Round 47 (Rated for Div. 2) ---- C Annoying Present
  16. 董树义 近代微波测量技术_本土IC领域又一关键技术获得突破!
  17. java的excel模板下载(解决中文名乱码问题)
  18. 实现顺序表各种基本运算的算法
  19. java 1 2 等于_java 判断语句中一个等于号和两个等于号的区别是什么?
  20. 计算机网络协议(二)——从二层到三层

热门文章

  1. CvSVM::EPS_SVR train_auto assertion sv_count != 0 failed原因
  2. mysql会话命令_mysql常用命令(持续更新)
  3. jointGrid,边际的颜色和hue保持一致,添加title
  4. 【三种可能问题】RuntimeError: cuDNN error: CUDNN_STATUS_NOT_SUPPORTED
  5. CUDA编程--并行矩阵向量乘法【80+行代码】
  6. 整数划分问题【递归以及递推求解方式】
  7. 【量化投资】策略八(聚宽)
  8. DIP第二章习题解答
  9. java方法体逻辑不会写怎么办,想自己写框架?不会写Java注解可不行
  10. Confluence 6 使用 WebDAV 客户端来对页面进行操作