视频1 视频21 视频41 视频61 视频文章1 视频文章21 视频文章41 视频文章61 推荐1 推荐3 推荐5 推荐7 推荐9 推荐11 推荐13 推荐15 推荐17 推荐19 推荐21 推荐23 推荐25 推荐27 推荐29 推荐31 推荐33 推荐35 推荐37 推荐39 推荐41 推荐43 推荐45 推荐47 推荐49 关键词1 关键词101 关键词201 关键词301 关键词401 关键词501 关键词601 关键词701 关键词801 关键词901 关键词1001 关键词1101 关键词1201 关键词1301 关键词1401 关键词1501 关键词1601 关键词1701 关键词1801 关键词1901 视频扩展1 视频扩展6 视频扩展11 视频扩展16 文章1 文章201 文章401 文章601 文章801 文章1001 资讯1 资讯501 资讯1001 资讯1501 标签1 标签501 标签1001 关键词1 关键词501 关键词1001 关键词1501 专题2001
sqlserver自定义分割月功能详解及实现代码
2020-11-09 07:00:55 责编:小采
文档


在最近的项目开发过程中,遇到了Sql server自动分割月的功能需求,这里在网上整理下资料.      

1、为何出现自定义分割月的需求

今天梳理一个平台的所有函数时,发现了一个自定义分割月函数,也就是指定分割月的开始日索引值(可以从1-31闭区间内的任何一个值)来获取指定日期所对应的分割月数值。这个函数当时是为了解决业务部门获取非标准月(标准月就是从每个月的第一天到最后一天组成一个完成的标准月份)的统计汇总数据的。例如:如果指定分割月的开始日索引值为5则表示某个月的5号到下个月的4号之间作为一个完整的分割月;同样地如果指定分割月的开始日索引值为1则表示标准月等等。 

我仔细梳理了这个函数进行了重构简化以及扩展,该自定义分割月函数的实现区别之前写的SQL Server时间粒度系列----第3节旬、月时间粒度详解文章中将一个整数值和月份日期相互转换功能,这个是按照标准月来实现的,虽然思路大致相同,但是并没有针对之前的月份日期和整数值转换函数对来进行扩展而是开发新的功能函数。也是为了尽量做到函数功能职责单一性、稳定性、可维护性以及可扩展性。 

2、sql server实现自定义分割月功能 

自定义分割月功能函数包括两个标量函数:ufn_SegMonths和ufn_SegMonth2Date。ufn_SegMonths获取指定的日期在自定义分割月对应的分割月数值;ufn_SegMonth2Date获取指定一个分割月数值赌对应的月份日期。 

sql server 版本的实现T-SQL代码如下:

IF OBJECT_ID(N'[dbo].[ufn_SegMonths]', 'FN') IS NOT NULL
BEGIN
 DROP FUNCTION [dbo].[ufn_SegMonths];
END
GO
 
--==================================
-- 功能:根据自定义月开始索引值获取指定日期所在的自定义月数。
-- 说明:自定义分割月数 = 年整数值*100 + 当前所在分割月值。
-- 环境:SQL Server 2005+。
-- 调用:SET @intSegMonths = dbo.fn_SegMonths('2008-01-14', 15)。
-- 创建:XXXX-XX-XX XX:XX-XX:XX XXX 创建函数实现。
-- 修改:XXXX-XX-XX XX:XX-XX:XX XXX XXXXXXXX。
--==================================
CREATE FUNCTION [dbo].[ufn_SegMonths]
(
 @dtmDate AS DATETIME -- 日期
 ,@tntSegStartIndexOfMonth AS INT = 15 -- 自定义分割月开始索引值(1-31)
)
RETURNS INT
AS
BEGIN 
 IF (@tntSegStartIndexOfMonth = 0 OR @tntSegStartIndexOfMonth >= 32)
 BEGIN
 SET @tntSegStartIndexOfMonth = 15;
 END
 
 DECLARE
 @intYears AS INT
 ,@tntMonth AS TINYINT
 ,@sntDay AS SMALLINT; 
 SELECT
 @intYears = DATEDIFF(YEAR, '1900-01-01', @dtmDate)
 ,@tntMonth = DATEPART(MONTH, @dtmDate)
 ,@sntDay = DATEPART(DAY, @dtmDate);
 
 IF (@sntDay >= @tntSegStartIndexOfMonth)
 BEGIN
 SET @tntMonth = @tntMonth + 1; 
 END
 
 IF (@tntMonth > 12)
 BEGIN
 SELECT
 @intYears = @intYears + 1
 ,@tntMonth = @tntMonth - 12;
 END
 
 RETURN @intYears * 100 + @tntMonth;
END
GO
 
IF OBJECT_ID(N'[dbo].[ufn_SegMonths2Date]', 'FN') IS NOT NULL
BEGIN
 DROP FUNCTION [dbo].[ufn_SegMonths2Date];
END
GO
 
--==================================
-- 功能:获取自定义分割月数对应的自定义分割月日期。
-- 说明:自定义分割月日期 = 自定义分割月数/100对应的年整数日期“组合”当前所在分割月值。
-- 环境:SQL Server 2005+。
-- 调用:SET @dtmSegMonthDate = dbo.fn_SegMonths2Date(11602)。
-- 创建:XXXX-XX-XX XX:XX-XX:XX XXX 创建函数实现。
-- 修改:XXXX-XX-XX XX:XX-XX:XX XXX XXXXXXXX。;
--==================================
CREATE FUNCTION [dbo].[ufn_SegMonths2Date]
(
 @intSegMonths AS INT -- 自定义分割月数
)
RETURNS DATETIME
AS
BEGIN 
 DECLARE @dtmDefaultBasedate AS DATETIME;
 SET @dtmDefaultBasedate = '1900-01-01';
 
 IF ((@intSegMonths IS NULL) OR (@intSegMonths <= 0))
 BEGIN
 RETURN @dtmDefaultBasedate;
 END
 
 DECLARE
 @intYears AS INT
 ,@intMonth AS INT; 
 SELECT
 @intYears = @intSegMonths / 100
 ,@intMonth = @intSegMonths % 100; 
 
 RETURN DATEADD(MONTH, @intMonth - 1, DATEADD(YEAR, @intYears, @dtmDefaultBasedate));
END
GO
 

3、测试验证效果

 针对以上简单的测试代码如下:

DECLARE
 @dtmStartDate AS DATETIME
 ,@dtmEndDate AS DATETIME;
 
SELECT
 @dtmStartDate = '2000-01-01'
 ,@dtmEndDate = '2016-12-31';
 
SELECT
 [T1].*
 ,[dbo].[ufn_SegMonths2Date]([T1].[SegMonths]) AS SegMonthDate
FROM (
 SELECT
 [T].[CDate]
 ,[dbo].[ufn_SegMonths]([T].[CDate], 28) AS SegMonths
 
 FROM (
 SELECT
 DATEADD(DAY, [Num], @dtmStartDate) AS CDate
 FROM
 [dbo].[ufn_GetNums](0, DATEDIFF(DAY, @dtmStartDate, @dtmEndDate))
 ) AS T
 WHERE [T].[CDate] BETWEEN '2014-12-01' AND '2016-03-31'
) AS T1
WHERE DATEPART(DAY, [T1].[CDate]) >= 27
GO

效果截图如下:

 注意:以上测试代码使用了SQL Server数字辅助表的实现这边文章的内联表值函数ufn_GetNums。

 4、总结语

这次是梳理平台的功能性函数所进行的重构简化以及扩展的实现。尽量将日期有关的功能函数梳理出来,便于直接在sql server用户数据库中来使用, 也便于BI仓库中使用。国庆一来已经过去一周,原来打算一周一遍的计划还是延期啦,再次严重检讨自己。

  感谢阅读,希望能帮助到大家,谢谢大家对本站的支持!

您可能感兴趣的文章:

  • SqlServer中如何解决session阻塞问题
  • SqlServer 英文单词全字匹配详解及实现代码
  • SqlServer编写数据库表的操作方式(建库、建表、修改语句)
  • C#访问SQLServer增删改查代码实例
  • SqlServer查询和Kill进程死锁的语句
  • 获取SqlServer存储过程定义的三种方法
  • SQLServer主键和唯一约束的区别
  • SqlServer存储过程实现及拼接sql的注意点
  • win2008 r2 服务器php+mysql+sqlserver2008运行环境配置(从安装、优化、安全等)
  • SQLSERVER简单创建DBLINK操作远程服务器数据库的方法
  • SqlServer2008误操作数据(delete或者update)后恢复数据的方法
  • 下载本文
    显示全文
    专题