我的表1有3列id,startdate和enddate。如果订单ID是主键,如何列出日期范围Startdate和Enddate之间的日期?
我有什么:
id Startdate EndDate
1 2/11/2014 2/13/2014
2 2/15/2014 2/17/2014
我需要什么:
id Date
1 2/11/2014
1 2/12/2014
1 2/13/2014
2 2/15/2014
2 2/16/2014
2 2/17/2014
我该怎么做?
答案 0 :(得分:2)
使用递归CTE:
WITH tmp AS (
SELECT id, StartDate AS [Date], EndDate
FROM MyTable
UNION ALL
SELECT tmp.id, DATEADD(DAY,1,tmp.[Date]), tmp.EndDate
FROM tmp
WHERE tmp.[Date] < tmp.EndDate
)
SELECT tmp.ID, tmp.[Date]
FROM tmp
ORDER BY tmp.id, tmp.[Date]
OPTION (MAXRECURSION 0) -- For long intervals
如果你必须使用游标/循环,大多数时候你做错了。
答案 1 :(得分:0)
如果您按Why should I consider using an auxiliary calendar table?所示进行辅助日历表的一次性设置,如果您不需要它们,可能会省略很多列,如下所示:
CREATE TABLE dbo.Calendar
(
dt SMALLDATETIME NOT NULL
PRIMARY KEY CLUSTERED,
Y SMALLINT,
M TINYINT,
D TINYINT
)
GO
SET NOCOUNT ON
DECLARE @dt SMALLDATETIME
SET @dt = '20000101'
WHILE @dt < '20300101'
BEGIN
INSERT dbo.Calendar(dt) SELECT @dt
SET @dt = @dt + 1
END;
UPDATE dbo.Calendar SET
Y = YEAR(dt),
M = MONTH(dt),
D = DAY(dt);
(根本不需要Y,M,D列,但我留下了这些列以显示可以存储更多数据以便快速访问 - 我链接的文章显示了如何使用它。)< / p>
然后,如果您的表名为“so”,那么您的代码将只是
SELECT A.id, C.dt
FROM so AS A
JOIN Calendar AS C
ON C.dt >= A.StartDate AND C.dt<= A.EndDate
使用这样的辅助表的一个好处是您的查询可以更快:在设置一个时完成的工作是一次性成本,这在使用期间不会发生..
答案 2 :(得分:0)
可以使用下面的查询来获取两个日期范围之间的日期列表,而不是使用CTE(在日期范围很大时过度递归和执行)。
DECLARE @StartDateSTR AS VARCHAR(32); DECLARE @EndDateSTR AS VARCHAR(32); DECLARE @EndDate AS DATE; DECLARE @StartDate AS DATE;
SET @StartDateSTR = '01 / 01/1990'; SET @EndDateSTR = '03 / 31/2025';组 @StartDate = CAST(@StartDateSTR AS date); SET @EndDate = cast(@EndDateSTR AS date);选择 DATEADD(DAY,n1.rn - 1,@ StartDate)AS dt FROM(SELECT rn = Row_number()OVER(ORDER BY(SELECT NULL))FROM sys.objects a CROSS JOIN sys.objects b CROSS JOIN sys.objects c CROSS JOIN sys.objects d)as n1 WHERE n1。[rn]&lt; = Datediff(dd,@ StartDate, @EndDate)+1;