/*
功能:按报表格式显示(行转列、定制、批量数据产生)
作者:王召冠
时间:2010-01-25 20:10
说明:此例子也是多种sql技术的综合应用
问题:假设有张考勤表(tb)如下:
姓名 考勤日期 考勤次数
张三 2010-01-01 2
张三 2010-01-02 3
张三 2010-01-03 1
张三 2010-01-01 1
李四 2010-01-02 2
李四 2010-01-03 2
想变成(得到如下结果):按指定时间段显示考勤报表
姓名 2010-01-01 2010-01-02 2010-01-03 2010-01-04 ... 汇总
---- ---------- ---------- ---------- ---------- ----
李四 0 2 2 0 4
张三 3 3 1 0 7
汇总 3 5 3 0 11
----------------------------------------------------------
*/
CREATE TABLE tb(vName NVARCHAR(10), dtDate DATETIME, iNum INT)
GO
INSERT INTO tb
VALUES ( '张三', '2010-01-01', 2 )
INSERT INTO tb
VALUES ( '张三', '2010-01-02', 3 )
INSERT INTO tb
VALUES ( '张三', '2010-01-03', 1 )
INSERT INTO tb
VALUES ( '张三', '2010-01-01', 1 )
INSERT INTO tb
VALUES ( '李四', '2010-01-02', 2 )
INSERT INTO tb
VALUES ( '李四', '2010-01-03', 2 )
GO
--SELECT *
--FROM tb
--SQL SERVER 动态SQL
DECLARE @dtBegin DATETIME, @dtEnd DATETIME
SELECT @dtBegin = '2010-01-01', @dtEnd = '2010-01-31'
SET NOCOUNT ON
/*
此处代码功能说明:
根据指定的时间段,快速生成一个不间断的时间序列表
具体实现特性说明:
每循环一次生成2的n次方条记录,减少循环次数。
注:
从实际应用上来说,在此处没有太明显的效果和意义;仅仅体现一种优化算法而已。
*/
DECLARE @iRank INT
SET @iRank = 1
DECLARE @tmp TABLE(dtDate DATETIME)
INSERT INTO @tmp ( dtDate ) VALUES ( @dtBegin )
WHILE DATEADD(DAY, POWER(2, (@iRank-1)), @dtBegin) <= @dtEnd
BEGIN
INSERT INTO @tmp ( dtDate )
SELECT DATEADD(DAY, POWER(2, (@iRank-1)), dtDate)
FROM @tmp
WHERE DATEADD(DAY, POWER(2, @iRank-1), dtDate) <= @dtEnd
SET @iRank = @iRank + 1
END
/*
此处代码功能说明:
根据时间序列表,生成动态SQL
注:
之所以将动态sql分到两个变量里,主要是尽量避免8000个字符的限制
*/
DECLARE @sql_a VARCHAR(8000)
SET @sql_a = 'select vName'
SELECT @sql_a = @sql_a
+ ', sum(case dtDate when ''' + CONVERT(NVARCHAR(10), dtDate, 120)
+ ''' then iNum else 0 end) [' + CONVERT(NVARCHAR(10), dtDate, 120) + ']'
FROM @tmp AS a
SET @sql_a = @sql_a + ', sum(iNum) as iTotal from tb group by vName'
--EXEC(@sql_a)
DECLARE @sql_b VARCHAR(8000)
SET @sql_b = 'select ''total'''
SELECT @sql_b = @sql_b + ', isnull((select sum(iNum) from tb where dtDate=''' + CONVERT(NVARCHAR(10), dtDate, 120) + '''), 0)'
FROM @tmp
ORDER BY dtDate
SET @sql_b = @sql_b + ', (select sum(iNum) from tb)'
--EXEC(@sql_b)
EXEC('select * from (' + @sql_a + ' union ' + @sql_b + ') as a order by a.iTotal')
GO
功能:按报表格式显示(行转列、定制、批量数据产生)
作者:王召冠
时间:2010-01-25 20:10
说明:此例子也是多种sql技术的综合应用
问题:假设有张考勤表(tb)如下:
姓名 考勤日期 考勤次数
张三 2010-01-01 2
张三 2010-01-02 3
张三 2010-01-03 1
张三 2010-01-01 1
李四 2010-01-02 2
李四 2010-01-03 2
想变成(得到如下结果):按指定时间段显示考勤报表
姓名 2010-01-01 2010-01-02 2010-01-03 2010-01-04 ... 汇总
---- ---------- ---------- ---------- ---------- ----
李四 0 2 2 0 4
张三 3 3 1 0 7
汇总 3 5 3 0 11
----------------------------------------------------------
*/
CREATE TABLE tb(vName NVARCHAR(10), dtDate DATETIME, iNum INT)
GO
INSERT INTO tb
VALUES ( '张三', '2010-01-01', 2 )
INSERT INTO tb
VALUES ( '张三', '2010-01-02', 3 )
INSERT INTO tb
VALUES ( '张三', '2010-01-03', 1 )
INSERT INTO tb
VALUES ( '张三', '2010-01-01', 1 )
INSERT INTO tb
VALUES ( '李四', '2010-01-02', 2 )
INSERT INTO tb
VALUES ( '李四', '2010-01-03', 2 )
GO
--SELECT *
--FROM tb
--SQL SERVER 动态SQL
DECLARE @dtBegin DATETIME, @dtEnd DATETIME
SELECT @dtBegin = '2010-01-01', @dtEnd = '2010-01-31'
SET NOCOUNT ON
/*
此处代码功能说明:
根据指定的时间段,快速生成一个不间断的时间序列表
具体实现特性说明:
每循环一次生成2的n次方条记录,减少循环次数。
注:
从实际应用上来说,在此处没有太明显的效果和意义;仅仅体现一种优化算法而已。
*/
DECLARE @iRank INT
SET @iRank = 1
DECLARE @tmp TABLE(dtDate DATETIME)
INSERT INTO @tmp ( dtDate ) VALUES ( @dtBegin )
WHILE DATEADD(DAY, POWER(2, (@iRank-1)), @dtBegin) <= @dtEnd
BEGIN
INSERT INTO @tmp ( dtDate )
SELECT DATEADD(DAY, POWER(2, (@iRank-1)), dtDate)
FROM @tmp
WHERE DATEADD(DAY, POWER(2, @iRank-1), dtDate) <= @dtEnd
SET @iRank = @iRank + 1
END
/*
此处代码功能说明:
根据时间序列表,生成动态SQL
注:
之所以将动态sql分到两个变量里,主要是尽量避免8000个字符的限制
*/
DECLARE @sql_a VARCHAR(8000)
SET @sql_a = 'select vName'
SELECT @sql_a = @sql_a
+ ', sum(case dtDate when ''' + CONVERT(NVARCHAR(10), dtDate, 120)
+ ''' then iNum else 0 end) [' + CONVERT(NVARCHAR(10), dtDate, 120) + ']'
FROM @tmp AS a
SET @sql_a = @sql_a + ', sum(iNum) as iTotal from tb group by vName'
--EXEC(@sql_a)
DECLARE @sql_b VARCHAR(8000)
SET @sql_b = 'select ''total'''
SELECT @sql_b = @sql_b + ', isnull((select sum(iNum) from tb where dtDate=''' + CONVERT(NVARCHAR(10), dtDate, 120) + '''), 0)'
FROM @tmp
ORDER BY dtDate
SET @sql_b = @sql_b + ', (select sum(iNum) from tb)'
--EXEC(@sql_b)
EXEC('select * from (' + @sql_a + ' union ' + @sql_b + ') as a order by a.iTotal')
GO
分类:
SQL Server
, 使用技巧
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· AI与.NET技术实操系列(二):开始使用ML.NET
· 记一次.NET内存居高不下排查解决与启示
· 探究高空视频全景AR技术的实现原理
· 理解Rust引用及其生命周期标识(上)
· 浏览器原生「磁吸」效果!Anchor Positioning 锚点定位神器解析
· DeepSeek 开源周回顾「GitHub 热点速览」
· 物流快递公司核心技术能力-地址解析分单基础技术分享
· .NET 10首个预览版发布:重大改进与新特性概览!
· AI与.NET技术实操系列(二):开始使用ML.NET
· 单线程的Redis速度为什么快?