【问题标题】:SQL stored procedure: increment months from a starting date to an end dateSQL 存储过程:从开始日期到结束日期递增月份
【发布时间】:2015-09-04 05:35:43
【问题描述】:

我正在尝试在 SQL Server 中创建一个存储过程,它基本上将从给定开始日期到给定结束日期的月份递增,并将它们更新到预定义的表中。

问题: 有点像这样:

Exec MonthRunner @Start ='2014-01-01', @End = '2014-06-01'

应该给我一张这样的桌子:

Date 
2014-01-01
2014-02-01
2015-03-01
2015-04-01
2015-05-01
2015-06-01

方法: 使用光标编程的循环。类似的东西:

Create Procedure MonthRunner(@Start date, @End date)
AS
DECLARE @Date date
DECLARE @getid CURSOR


SET @getid = CURSOR FOR
Select (@Start)


Set @getid 
OPEN @getid 
FETCH NEXT
FROM @getid into @Date


WHILE @@FETCH_STATUS = 0
BEGIN
SET @Date = (Select Dateadd(Month, 1, @Date))
DECLARE @sqlrun varchar(max)

SET @sqlrun= 'Update myTable' + 'Set Date=' + @Date
EXEC @sqlrun


fetch next 
from @getid into @Date
END

CLOSE @getid
DEALLOCATE @getid

到目前为止我的结果是:

Update myTable Set Date='2014-02-01'

但是没有循环,我也不知道如何使用变量@End 终止循环。

您的帮助将不胜感激! 提前致谢,

克莱门斯

【问题讨论】:

  • 该死,我太专注于我的光标,以至于我忘记了如何循环。
  • 用户 Alivia 提供的 CTE 解决方案即可。这可能是最好的一个。最重要的是,尽可能避免使用光标。

标签: sql-server tsql date stored-procedures cursor


【解决方案1】:

这可以通过递归 CTE 轻松完成:

;WITH cte AS (
    SELECT      @Start      AS [Month]
    UNION ALL
    SELECT      DATEADD(MONTH, 1, [Month])
    FROM        cte
    WHERE       [Month] < @End
)

SELECT  [Month]
FROM    cte
OPTION  (MAXRECURSION 0)

【讨论】:

    【解决方案2】:

    我循环类似这样:

    DECLARE @Start date
    DECLARE @End date 
    DECLARE @counter date
    
    set @counter = @Start
        while @counter <= @End
        begin
              print 'The counter is ' + cast(@counter as char)
             set @counter = (Select Dateadd(Month, 1, @counter))
        end
    

    您如何看待这个解决方案? (当然要改文字)

    【讨论】:

    • 为什么要在 SQL 中循环?效率极低……我渴望循环效果,但 SQL 就是处理集合,所以你想远离这样的命令式代码。
    【解决方案3】:

    在 sp 中从开始日期到结束日期递增月份

    ALTER PROCEDURE "dbo"."monthIncrementSp"
    AS
        DECLARE @startDate VARCHAR(50);
        DECLARE @endDate VARCHAR(50);
    
        SET @startDate = '01-01-2017';
        SET @endDate = '31-12-2017';
    
        SELECT TOP (DATEDIFF(MONTH, CONVERT(DATE, @startDate, 105),CONVERT(DATE, @endDate, 105))+1)
        DATEADD(MONTH, ROW_NUMBER() OVER (ORDER BY name)-1, CONVERT(DATE, @startDate, 105))
        FROM sys.all_columns
    

    【讨论】:

      【解决方案4】:

      这是一个获取月初的表值函数:

      CREATE FUNCTION dbo.MonthBegin (   
          @date DATE = NULL
        , @offset INT = 0
      )
      RETURNS TABLE   
      AS   
      RETURN (
          SELECT D = DATEADD(m, DATEDIFF(m, 0, @date) + @offset, 0)
      );
      

      单独使用这个功能并不能完全满足您的需求。不过,将它与一组整数结合起来,您会获得很多乐趣:

      DECLARE @seedDate DATE = GETDATE();
      
      SELECT *
      FROM dbo.RangeInt(-100, 100) Nums
      CROSS APPLY dbo.MonthBegin(@seedDate, Nums.N) Dates;
      

      上面的示例使用 TVF 生成一组介于 -100 和 100 之间的数字,然后将这些数字传递给 MonthBegin TVF(连同种子日期)。您也可以根据数字表或 CTE 编写此内容...任何您最熟悉/最舒服的内容。

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2021-08-18
        • 1970-01-01
        • 2014-03-02
        • 1970-01-01
        相关资源
        最近更新 更多