为了账号安全,请及时绑定邮箱和手机立即绑定

如何在SQL Server中生成日期范围

如何在SQL Server中生成日期范围

呼唤远方 2019-11-03 04:04:44
标题并不能完全反映我的意思,这可能是重复的。这是一个很长的版本:给定客人的姓名,他们的注册日期和他们的退房日期,如何为他们每天作为客人生成一行?例:鲍勃签入7/14,然后离开7/17。我想要('Bob', 7/14), ('Bob', 7/15), ('Bob', 7/16), ('Bob', 7/17) 作为我的结果。谢谢!
查看完整描述

3 回答

?
SMILET

TA贡献1796条经验 获得超4个赞

我认为,为此特定目的,以下查询与使用专用查找表一样有效。


DECLARE @start DATE, @end DATE;

SELECT @start = '20110714', @end = '20110717';


;WITH n AS 

(

  SELECT TOP (DATEDIFF(DAY, @start, @end) + 1) 

    n = ROW_NUMBER() OVER (ORDER BY [object_id])

  FROM sys.all_objects

)

SELECT 'Bob', DATEADD(DAY, n-1, @start)

FROM n;

结果:


Bob     2011-07-14

Bob     2011-07-15

Bob     2011-07-16

Bob     2011-07-17

大概您需要将此作为一个集合,而不是单个成员,因此这里是一种适应此技术的方法:


DECLARE @t TABLE

(

    Member NVARCHAR(32), 

    RegistrationDate DATE, 

    CheckoutDate DATE

);


INSERT @t SELECT N'Bob', '20110714', '20110717'

UNION ALL SELECT N'Sam', '20110712', '20110715'

UNION ALL SELECT N'Jim', '20110716', '20110719';


;WITH [range](d,s) AS 

(

  SELECT DATEDIFF(DAY, MIN(RegistrationDate), MAX(CheckoutDate))+1,

    MIN(RegistrationDate)

    FROM @t -- WHERE ?

),

n(d) AS

(

  SELECT DATEADD(DAY, n-1, (SELECT MIN(s) FROM [range]))

  FROM (SELECT ROW_NUMBER() OVER (ORDER BY [object_id])

  FROM sys.all_objects) AS s(n)

  WHERE n <= (SELECT MAX(d) FROM [range])

)

SELECT t.Member, n.d

FROM n CROSS JOIN @t AS t

WHERE n.d BETWEEN t.RegistrationDate AND t.CheckoutDate;

----------^^^^^^^ not many cases where I'd advocate between!

结果:


Member    d

--------  ----------

Bob       2011-07-14

Bob       2011-07-15

Bob       2011-07-16

Bob       2011-07-17

Sam       2011-07-12

Sam       2011-07-13

Sam       2011-07-14

Sam       2011-07-15

Jim       2011-07-16

Jim       2011-07-17

Jim       2011-07-18

Jim       2011-07-19

正如@Dems指出的那样,这可以简化为:


;WITH natural AS 

(

  SELECT ROW_NUMBER() OVER (ORDER BY [object_id]) - 1 AS val 

  FROM sys.all_objects

SELECT t.Member, d = DATEADD(DAY, natural.val, t.RegistrationDate) 

  FROM @t AS t INNER JOIN natural 

  ON natural.val <= DATEDIFF(DAY, t.RegistrationDate, t.CheckoutDate);



查看完整回答
反对 回复 2019-11-04
?
POPMUISE

TA贡献1765条经验 获得超5个赞

我通常在某些表上使用row_number()来达到目的。所以:


select t.name, dateadd(d, seq.seqnum, t.start_date)

from t left outer join

     (select row_number() over (order by (select NULL)) as seqnum

      from t

     ) seq

     on seqnum <= datediff(d, t.start_date, t.end_date)

seq的计算非常快,因为不需要计算或排序。但是,您需要确保该表对于所有时间段都足够大。



查看完整回答
反对 回复 2019-11-04
  • 3 回答
  • 0 关注
  • 573 浏览
慕课专栏
更多

添加回答

举报

0/150
提交
取消
意见反馈 帮助中心 APP下载
官方微信