sql server 自定义分割月功能详解及实现代码

所属分类: 数据库 / MsSql 阅读数: 198
收藏 0 赞 0 分享

在最近的项目开发过程中,遇到了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仓库中使用。国庆一来已经过去一周,原来打算一周一遍的计划还是延期啦,再次严重检讨自己。

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

更多精彩内容其他人还在看

SQL Server评估期已过问题的解决方法

这篇文章主要为大家详细介绍了SQL Server评估期已过问题的解决方法,感兴趣的小伙伴们可以参考一下
收藏 0 赞 0 分享

sqlserver还原数据库的时候出现提示无法打开备份设备的解决方法(设备出现错误或设备脱)

今天在恢复数据库的时候,因为是异地部分还原,出现提示 无法打开备份设备 E:\自动备份\ufidau8xTmp\UFDATA.BAK 。设备出现错误或设备脱,这里分享一下解决方法,需要的朋友可以参考一下
收藏 0 赞 0 分享

SQL数据库存储过程示例解析

这篇文章主要针对SQL数据库存储过程示例进行解析,感兴趣的小伙伴们可以参考一下
收藏 0 赞 0 分享

SQL Server 2012 安全概述

这篇文章给你概括介绍了SQL Server 2012里的基本安全概念。你学到了一些常见的数据威胁,探寻了SQL Server背后的设计理念,学习了在整个系列文章看到的一些安全术语,算是一篇比较非公式化的开篇,希望能够勾引起大家对于sql安全的兴趣
收藏 0 赞 0 分享

探讨select in 在postgresql的效率问题

这篇文章主要介绍了探讨select in 在postgresql的效率问题 的相关资料,需要的朋友可以参考下
收藏 0 赞 0 分享

SQL Server 2012 身份验证(Authentication)

这篇SQL Server安全文章,我们学习了SQL Server里的多个验证选项。Windows集成身份验证是最安全的,但并不是都是可行的,微软多年来已经让SQL Server验证更加安全。
收藏 0 赞 0 分享

SQL性能优化之定位网络性能问题的方法(DEMO)

这篇文章主要介绍了SQL性能优化之定位网络性能问题的方法的相关资料,需要的朋友可以参考下
收藏 0 赞 0 分享

SQL Server 2016里的sys.dm_exec_input_buffer的问题

这篇文章主要介绍了SQL Server 2016里的sys.dm_exec_input_buffer的相关资料,需要的朋友可以参考下
收藏 0 赞 0 分享

SQL Server删除表及删除表中数据的方法

本文介绍SQL Server中如何删除表,如何删除表中的数据。在删除表数据时有delete和truncate两种方法,delete和truncate有什么区别呢
收藏 0 赞 0 分享

sqlserver 因为选定的用户拥有对象,所以无法除去该用户的解决方法

这篇文章主要介绍了sqlserver 因为选定的用户拥有对象,所以无法除去该用户,因为是附加数据库选择了与源服务器一样的用户导致
收藏 0 赞 0 分享
查看更多