如何创建递归查询以获取两个日期之间的所有日期
How to create recursive query to get all dates between two dates
我想获取两个日期 arrival date
和 leaving date
之间的所有日期。
我试过那个递归查询,但没用。
;with dates as (
SELECT GuestID, ArrivalDate as reserveddate
from dbo.Guest
union all
SELECT GuestID, dateadd (day,1,dbo.Guest. ArrivalDate) as reserveddate
from dbo.Guest
where dateadd (day,1,dbo.Guest. ArrivalDate) <dbo.Guest.leavingate
)
SELECT *
from dates
option (maxrecursion 0)
您需要递归 CTE:
DECLARE @arrival_date date = '2016-01-01',
@leaving_date date = '2016-02-01'
;WITH cte AS (
SELECT @arrival_date as date_
UNION ALL
SELECT CAST(DATEADD(day,1,date_) as date)
FROM cte
WHERE date_ < @leaving_date
)
SELECT *
FROM cte
OPTION (MAXRECURSION 0)
输出:
date_
2016-01-01
2016-01-02
2016-01-03
...
2016-01-30
2016-01-31
2016-02-01
EDIT1
根据您的样本:
;WITH cte AS (
SELECT GuestID, CAST(ArrivalDate as date) as date_
FROM Guests
UNION ALL
SELECT c.GuestID, CAST(DATEADD(day,1,date_) as date)
FROM cte c
INNER JOIN Guests g
ON g.GuestID = c.GuestID
WHERE date_ < g.LeavingDate
)
SELECT *
FROM cte
ORDER BY GuestID, date_
OPTION (MAXRECURSION 0)
EDIT2
;WITH Guests AS (
SELECT 1 as GuestID,
'2016-01-01' ArrivalDate,
'2016-01-05' LeavingDate
UNION ALL
SELECT 2 ,
'2016-06-17',
'2016-06-20'
), cte AS (
SELECT GuestID, CAST(ArrivalDate as date) as date_
FROM Guests
UNION ALL
SELECT c.GuestID, CAST(DATEADD(day,1,date_) as date)
FROM cte c
INNER JOIN Guests g
ON g.GuestID = c.GuestID
WHERE date_ < g.LeavingDate
)
SELECT *
FROM cte
ORDER BY GuestID, date_
OPTION (MAXRECURSION 0)
输出:
GuestID date_
1 2016-01-01
1 2016-01-02
1 2016-01-03
1 2016-01-04
1 2016-01-05
2 2016-06-17
2 2016-06-18
2 2016-06-19
2 2016-06-20
我对这类事情的偏好是使用计数 table。我会查看每个看起来像这样的系统。
create View [dbo].[cteTally] as
WITH
E1(N) AS (select 1 from (values (1),(1),(1),(1),(1),(1),(1),(1),(1),(1))dt(n)),
E2(N) AS (SELECT 1 FROM E1 a, E1 b), --10E+2 or 100 rows
E4(N) AS (SELECT 1 FROM E2 a, E2 b), --10E+4 or 10,000 rows max
cteTally(N) AS
(
SELECT ROW_NUMBER() OVER (ORDER BY (SELECT NULL)) FROM E4
)
select N from cteTally
GO
这样一来,我就可以随时掌握 table 的计数。您可以在此处阅读有关 tally tables 以及它们如何替换循环的更多信息。 http://www.sqlservercentral.com/articles/T-SQL/62867/
要解决您当前的问题,这变得相当简单。首先我们需要一个 table 和一些示例数据。
create table #Guest
(
GuestID int identity
, ArrivalDate date
, DepartureDate date
)
insert #Guest
select '2016-06-01', '2016-06-15' union all
select '2016-07-01', '2016-07-12'
这里是理货 table 真正显示力量的地方。为您的挑战生成输出就像这段代码一样简单。
SELECT GuestID
, ArrivalDate
, DepartureDate
, DATEADD(Day, N - 1, ArrivalDate) as EachDate
from #Guest g
join cteTally t on t.N <= DATEDIFF(day, ArrivalDate, DepartureDate) + 1
order by GuestID
, EachDate
与递归 cte 相比,这种方法的另一大优势是您使用的是所谓的三角连接,可能会带来一些性能挑战。这是有关三角连接的更多信息。 http://www.sqlservercentral.com/articles/T-SQL/61539/
试试这个
DECLARE @DateFrom DateTime = DATEADD(DAY,DATEDIFF(DAY,0,GETDATE())-5,0)
DECLARE @DateTo DateTime = CONVERT(DATE,GETDATE())
;WITH Numbers (Number) AS (
SELECT row_number() OVER (ORDER BY object_id)
FROM sys.all_objects
)
SELECT dateadd(DAY, number-1, @DateFrom)
FROM Numbers
WHERE number <= datediff(DAY, @DateFrom-1, @DateTo-1)
您可以通过在 select dateadd 和 where datediff
中将 DAY 更改为 WEEK、MONTH、YEAR 等来更改日期间隔
我想获取两个日期 arrival date
和 leaving date
之间的所有日期。
我试过那个递归查询,但没用。
;with dates as (
SELECT GuestID, ArrivalDate as reserveddate
from dbo.Guest
union all
SELECT GuestID, dateadd (day,1,dbo.Guest. ArrivalDate) as reserveddate
from dbo.Guest
where dateadd (day,1,dbo.Guest. ArrivalDate) <dbo.Guest.leavingate
)
SELECT *
from dates
option (maxrecursion 0)
您需要递归 CTE:
DECLARE @arrival_date date = '2016-01-01',
@leaving_date date = '2016-02-01'
;WITH cte AS (
SELECT @arrival_date as date_
UNION ALL
SELECT CAST(DATEADD(day,1,date_) as date)
FROM cte
WHERE date_ < @leaving_date
)
SELECT *
FROM cte
OPTION (MAXRECURSION 0)
输出:
date_
2016-01-01
2016-01-02
2016-01-03
...
2016-01-30
2016-01-31
2016-02-01
EDIT1
根据您的样本:
;WITH cte AS (
SELECT GuestID, CAST(ArrivalDate as date) as date_
FROM Guests
UNION ALL
SELECT c.GuestID, CAST(DATEADD(day,1,date_) as date)
FROM cte c
INNER JOIN Guests g
ON g.GuestID = c.GuestID
WHERE date_ < g.LeavingDate
)
SELECT *
FROM cte
ORDER BY GuestID, date_
OPTION (MAXRECURSION 0)
EDIT2
;WITH Guests AS (
SELECT 1 as GuestID,
'2016-01-01' ArrivalDate,
'2016-01-05' LeavingDate
UNION ALL
SELECT 2 ,
'2016-06-17',
'2016-06-20'
), cte AS (
SELECT GuestID, CAST(ArrivalDate as date) as date_
FROM Guests
UNION ALL
SELECT c.GuestID, CAST(DATEADD(day,1,date_) as date)
FROM cte c
INNER JOIN Guests g
ON g.GuestID = c.GuestID
WHERE date_ < g.LeavingDate
)
SELECT *
FROM cte
ORDER BY GuestID, date_
OPTION (MAXRECURSION 0)
输出:
GuestID date_
1 2016-01-01
1 2016-01-02
1 2016-01-03
1 2016-01-04
1 2016-01-05
2 2016-06-17
2 2016-06-18
2 2016-06-19
2 2016-06-20
我对这类事情的偏好是使用计数 table。我会查看每个看起来像这样的系统。
create View [dbo].[cteTally] as
WITH
E1(N) AS (select 1 from (values (1),(1),(1),(1),(1),(1),(1),(1),(1),(1))dt(n)),
E2(N) AS (SELECT 1 FROM E1 a, E1 b), --10E+2 or 100 rows
E4(N) AS (SELECT 1 FROM E2 a, E2 b), --10E+4 or 10,000 rows max
cteTally(N) AS
(
SELECT ROW_NUMBER() OVER (ORDER BY (SELECT NULL)) FROM E4
)
select N from cteTally
GO
这样一来,我就可以随时掌握 table 的计数。您可以在此处阅读有关 tally tables 以及它们如何替换循环的更多信息。 http://www.sqlservercentral.com/articles/T-SQL/62867/
要解决您当前的问题,这变得相当简单。首先我们需要一个 table 和一些示例数据。
create table #Guest
(
GuestID int identity
, ArrivalDate date
, DepartureDate date
)
insert #Guest
select '2016-06-01', '2016-06-15' union all
select '2016-07-01', '2016-07-12'
这里是理货 table 真正显示力量的地方。为您的挑战生成输出就像这段代码一样简单。
SELECT GuestID
, ArrivalDate
, DepartureDate
, DATEADD(Day, N - 1, ArrivalDate) as EachDate
from #Guest g
join cteTally t on t.N <= DATEDIFF(day, ArrivalDate, DepartureDate) + 1
order by GuestID
, EachDate
与递归 cte 相比,这种方法的另一大优势是您使用的是所谓的三角连接,可能会带来一些性能挑战。这是有关三角连接的更多信息。 http://www.sqlservercentral.com/articles/T-SQL/61539/
试试这个
DECLARE @DateFrom DateTime = DATEADD(DAY,DATEDIFF(DAY,0,GETDATE())-5,0)
DECLARE @DateTo DateTime = CONVERT(DATE,GETDATE())
;WITH Numbers (Number) AS (
SELECT row_number() OVER (ORDER BY object_id)
FROM sys.all_objects
)
SELECT dateadd(DAY, number-1, @DateFrom)
FROM Numbers
WHERE number <= datediff(DAY, @DateFrom-1, @DateTo-1)
您可以通过在 select dateadd 和 where datediff
中将 DAY 更改为 WEEK、MONTH、YEAR 等来更改日期间隔