获取SQL Server中两个日期之间的所有日期

use*_*557 33 sql sql-server cursor

如何获取两个日期之间的日期?

我有一个变量@MAXDATE,它存储表中的最大日期.现在我想得到之间的所有日期@Maxdate,GETDATE()并希望将这些日期存储在游标中.

到目前为止,我做了如下:

;with GetDates As  
(  
select DATEADD(day,1,@maxDate) as TheDate
UNION ALL  
select DATEADD(day,1, TheDate) from GetDates  
where TheDate < GETDATE()  
)  
Run Code Online (Sandbox Code Playgroud)

这是完美的工作,但当我试图将这些值存储在游标中时

SET @DateCurSor=CURSOR FOR
                SELECT TheDate
                FROM GetDates
Run Code Online (Sandbox Code Playgroud)

编译错误

关键字"SET"附近的语法不正确.

怎么解决这个问题.

提前致谢

Gar*_*thD 56

我的第一个建议是使用您的日历表,如果您没有,请创建一个.它们非常有用.您的查询就像下面这样简单:

DECLARE @MinDate DATE = '20140101',
        @MaxDate DATE = '20140106';

SELECT  Date
FROM    dbo.Calendar
WHERE   Date >= @MinDate
AND     Date < @MaxDate;
Run Code Online (Sandbox Code Playgroud)

如果您不想或不能创建日历表,您仍然可以在没有递归CTE的情况下即时执行此操作:

DECLARE @MinDate DATE = '20140101',
        @MaxDate DATE = '20140106';

SELECT  TOP (DATEDIFF(DAY, @MinDate, @MaxDate) + 1)
        Date = DATEADD(DAY, ROW_NUMBER() OVER(ORDER BY a.object_id) - 1, @MinDate)
FROM    sys.all_objects a
        CROSS JOIN sys.all_objects b;
Run Code Online (Sandbox Code Playgroud)

如需进一步阅读,请参阅:

关于然后在光标中使用这个日期序列,我真的建议你找到另一种方法.通常有基于集合的替代方案,其性能会更好.

所以你的数据:

  date   | it_cd | qty 
24-04-14 |  i-1  | 10 
26-04-14 |  i-1  | 20
Run Code Online (Sandbox Code Playgroud)

要获得2014年4月28日的数量(我收集的是您的要求),您实际上并不需要上述任何一项,您可以简单地使用:

SELECT  TOP 1 date, it_cd, qty 
FROM    T
WHERE   it_cd = 'i-1'
AND     Date <= '20140428'
ORDER BY Date DESC;
Run Code Online (Sandbox Code Playgroud)

如果您不希望它用于特定项目:

SELECT  date, it_cd, qty 
FROM    (   SELECT  date, 
                    it_cd, 
                    qty, 
                    RowNumber = ROW_NUMBER() OVER(PARTITION BY ic_id 
                                                    ORDER BY date DESC)
            FROM    T
            WHERE   Date  <= '20140428'
        ) T
WHERE   RowNumber = 1;
Run Code Online (Sandbox Code Playgroud)

  • @PimBrouwers交叉连接的必要性在于需要多少行。如果所需的日期少于sys.all_objects中对象的数目,则不是必需的,但是如果日期范围跨越20年,则需要交叉联接。使用“ TOP(需要的天数)”意味着,当需要较少的行时,交叉连接的开销很小或没有开销,因此将其留在其中不会有任何危害。 (2认同)

Anv*_*esh 22

您可以使用此脚本查找两个日期之间的日期.参考本文:

DECLARE @StartDateTime DATETIME
DECLARE @EndDateTime DATETIME

SET @StartDateTime = '2015-01-01'
SET @EndDateTime = '2015-01-12';

WITH DateRange(DateData) AS 
(
    SELECT @StartDateTime as Date
    UNION ALL
    SELECT DATEADD(d,1,DateData)
    FROM DateRange 
    WHERE DateData < @EndDateTime
)
SELECT DateData
FROM DateRange
OPTION (MAXRECURSION 0)
GO
Run Code Online (Sandbox Code Playgroud)


Gol*_*hop 7

只是说......这是一个更简单的方法:

declare @sdate date = '2017-06-25'
    , @edate date = '2017-07-24';

with dates_CTE (date) as (
    select @sdate 
    Union ALL
    select DATEADD(day, 1, date)
    from dates_CTE
    where date < @edate
)
select *
from dates_CTE;
Run Code Online (Sandbox Code Playgroud)


小智 5

轻松创建一个表值函数,它将返回一个包含所有日期的表。 以字符串形式输入日期 您可以以您喜欢的格式自定义日期 '01/01/2017' 或 '01-01-2017' 字符串格式 (103,126 ...)

尝试这个

CREATE FUNCTION [dbo].[DateRange_To_Table] ( @minDate_Str NVARCHAR(30), @maxDate_Str NVARCHAR(30))

RETURNS  @Result TABLE(DateString NVARCHAR(30) NOT NULL, DateNameString NVARCHAR(30) NOT NULL)

AS

begin

    DECLARE @minDate DATETIME, @maxDate DATETIME
    SET @minDate = CONVERT(Datetime, @minDate_Str,103)
    SET @maxDate = CONVERT(Datetime, @maxDate_Str,103)


    INSERT INTO @Result(DateString, DateNameString )
    SELECT CONVERT(NVARCHAR(10),@minDate,103), CONVERT(NVARCHAR(30),DATENAME(dw,@minDate))



    WHILE @maxDate > @minDate
    BEGIN
        SET @minDate = (SELECT DATEADD(dd,1,@minDate))
        INSERT INTO @Result(DateString, DateNameString )
        SELECT CONVERT(NVARCHAR(10),@minDate,103), CONVERT(NVARCHAR(30),DATENAME(dw,@minDate))
    END




    return

end   
Run Code Online (Sandbox Code Playgroud)

要执行该功能,请执行以下操作:

SELECT * FROM dbo.DateRange_To_Table ('01/01/2017','31/01/2017')
Run Code Online (Sandbox Code Playgroud)

输出将是

01/01/2017  Sunday
02/01/2017  Monday
03/01/2017  Tuesday
04/01/2017  Wednesday
05/01/2017  Thursday
06/01/2017  Friday
07/01/2017  Saturday
08/01/2017  Sunday
09/01/2017  Monday
10/01/2017  Tuesday
11/01/2017  Wednesday
12/01/2017  Thursday
13/01/2017  Friday
14/01/2017  Saturday
15/01/2017  Sunday
16/01/2017  Monday
17/01/2017  Tuesday
18/01/2017  Wednesday
19/01/2017  Thursday
20/01/2017  Friday
21/01/2017  Saturday
22/01/2017  Sunday
23/01/2017  Monday
24/01/2017  Tuesday
25/01/2017  Wednesday
26/01/2017  Thursday
27/01/2017  Friday
28/01/2017  Saturday
29/01/2017  Sunday
30/01/2017  Monday
31/01/2017  Tuesday
Run Code Online (Sandbox Code Playgroud)