SQL日期范围查询-表比较
我有两个SQL Server表,其中包含以下信息: 表SQL日期范围查询-表比较,sql,sql-server,tsql,date,gaps-and-islands,Sql,Sql Server,Tsql,Date,Gaps And Islands,我有两个SQL Server表,其中包含以下信息: 表t\U场馆: 场馆id是唯一的 venue_id | start_date | end_date 1 | 01/01/2014 | 02/01/2014 2 | 05/01/2014 | 05/01/2014 3 | 09/01/2014 | 15/01/2014 4 | 20/01/2014 | 30/01/2014 表t\u venueuse
t\U场馆:
场馆id
是唯一的
venue_id | start_date | end_date
1 | 01/01/2014 | 02/01/2014
2 | 05/01/2014 | 05/01/2014
3 | 09/01/2014 | 15/01/2014
4 | 20/01/2014 | 30/01/2014
表t\u venueuser
:
场馆id
不唯一
venue_id | start_date | end_date
1 | 02/01/2014 | 02/01/2014
2 | 05/01/2014 | 05/01/2014
3 | 09/01/2014 | 10/01/2014
4 | 23/01/2014 | 25/01/2014
从这两个表中,我需要找到尚未为每个范围选择的日期,因此输出如下所示:
venue_id | start_date | end_date
1 | 01/01/2014 | 01/01/2014
3 | 11/01/2014 | 15/01/2014
4 | 20/01/2014 | 22/01/2014
4 | 26/01/2014 | 30/01/2014
我可以比较这两个表,并使用“except”从t\u ventions
获取要显示在我的查询中的日期范围,但我无法获取生成未选择日期的查询。任何帮助都将不胜感激。这是一个完整的破解,但它给出了您所需的结果,我仅根据您提供的数据进行了测试,因此可能会有更大的数据集
一般来说,您在这里要解决的是间隙和孤岛问题的变化,这是(简要地)缺少某些项的序列。缺少的项目称为间隙,现有项目称为孤岛。如果您想大致了解此问题,请查看以下几篇文章:
代码:
;with dates as
(
SELECT vdates.venue_id,
vdates.vdate
FROM ( SELECT DATEADD(d,sv.number,v.start_date) vdate
, v.venue_id
FROM t_venues v
INNER JOIN master..spt_values sv
ON sv.type='P'
AND sv.number BETWEEN 0 AND datediff(d, v.start_date, v.end_date)) vdates
LEFT JOIN t_venueuser vu
ON vdates.vdate >= vu.start_date
AND vdates.vdate <= vu.end_date
AND vdates.venue_id = vu.venue_id
WHERE ISNULL(vu.venue_id,-1) = -1
)
SELECT venue_id, ISNULL([1],[2]) StartDate, [2] EndDate
FROM (SELECT venue_id, rDate, ROW_NUMBER() OVER (PARTITION BY venue_id, DateType ORDER BY rDate) AS rType, DateType as dType
FROM( SELECT d1.venue_id
,d1.vdate AS rDate
,'1' AS DateType
FROM dates AS d1
LEFT JOIN dates AS d0
ON DATEADD(d,-1,d1.vdate) = d0.vdate
LEFT JOIN dates AS d2
ON DATEADD(d,1,d1.vdate) = d2.vdate
WHERE CASE ISNULL(d2.vdate, '01 Jan 1753') WHEN '01 Jan 1753' THEN '2' ELSE '1' END = 1
AND ISNULL(d0.vdate, '01 Jan 1753') = '01 Jan 1753'
UNION
SELECT d1.venue_id
,ISNULL(d2.vdate,d1.vdate)
,'2'
FROM dates AS d1
LEFT JOIN dates AS d2
ON DATEADD(d,1,d1.vdate) = d2.vdate
WHERE CASE ISNULL(d2.vdate, '01 Jan 1753') WHEN '01 Jan 1753' THEN '2' ELSE '1' END = 2
) res
) src
PIVOT (MIN (rDate)
FOR dType IN
( [1], [2] )
) AS pvt
venue_id StartDate EndDate
1 2014-01-01 2014-01-01
3 2014-01-11 2014-01-15
4 2014-01-20 2014-01-22
4 2014-01-26 2014-01-30
日历桌!
另一个完美的日历表候选人。如果你懒得去寻找一个
设置数据
询问
解释
我们的日历表包含每个日期的条目
我们加入我们的t\u场馆
(如果您有选择,请取消t\u
前缀!),每天在开始日期
和结束日期
之间返回。仅此连接的vention\u id=4
输出示例:
venue_id the_date
----------- -----------------------
4 2014-01-20 00:00:00.000
4 2014-01-21 00:00:00.000
4 2014-01-22 00:00:00.000
4 2014-01-23 00:00:00.000
4 2014-01-24 00:00:00.000
4 2014-01-25 00:00:00.000
4 2014-01-26 00:00:00.000
4 2014-01-27 00:00:00.000
4 2014-01-28 00:00:00.000
4 2014-01-29 00:00:00.000
4 2014-01-30 00:00:00.000
(11 row(s) affected)
现在我们每天有一行,我们[outer]加入我们的t\u venueuser
表。我们加入的方式与之前基本相同,但有一个额外的转折点:我们也需要基于场馆id
加入
为场馆\u id=4运行此操作将得到以下结果:
venue_id the_date t_venueuser_venue_id
----------- ----------------------- --------------------
4 2014-01-20 00:00:00.000 NULL
4 2014-01-21 00:00:00.000 NULL
4 2014-01-22 00:00:00.000 NULL
4 2014-01-23 00:00:00.000 4
4 2014-01-24 00:00:00.000 4
4 2014-01-25 00:00:00.000 4
4 2014-01-26 00:00:00.000 NULL
4 2014-01-27 00:00:00.000 NULL
4 2014-01-28 00:00:00.000 NULL
4 2014-01-29 00:00:00.000 NULL
4 2014-01-30 00:00:00.000 NULL
(11 row(s) affected)
查看如何为没有t\u venueuser
记录的行设置NULL
值。天才,不是吗<代码>;-)代码>
因此,在我的第一个查询中,我给了您一个快速的CASE语句,它显示了可用性(1=可用,0=不可用)。这仅用于说明,但可能对您有用
然后,您可以将查询包装起来,然后在此计算列上应用一个额外的筛选器,或者只需在:where t_venueuser.venue_id为NULL
中添加一个where子句,这将执行相同的操作。结果中的venue 3行不应该是2014年1月11日到2014年1月15日吗?是的,谢谢-好位置!如果答案有帮助的话,别忘了将其标记为已接受。这真是太棒了。非常感谢。我在一个更大的数据集上运行了它,我能找到的唯一问题是,当事件已经过去,并且在事件开始时有可用的日期时,它只显示1天?例如:场馆为2014年9月1日至2014年9月10日,且场馆用户已登记为2014年9月5日至2014年9月10日,输出将显示2014年9月4日至2014年9月4日?我正在玩它,看看能不能修好它@samhankin我很高兴我们能提供帮助,如果还有什么我们可以帮助的,请告诉我们。感谢您抽出时间来帮助我们!我已经尝试了这两种解决方案,它们都非常棒-谢谢!我学了很多@萨姆汉金很高兴我能帮上忙。如果您对代码有任何疑问,请询问,我将更新我的答案以填补任何空白:)
venue_id the_date is_available
----------- ----------------------- ------------
1 2014-01-01 00:00:00.000 1
1 2014-01-02 00:00:00.000 0
2 2014-01-05 00:00:00.000 0
3 2014-01-09 00:00:00.000 0
3 2014-01-10 00:00:00.000 0
3 2014-01-11 00:00:00.000 1
3 2014-01-12 00:00:00.000 1
3 2014-01-13 00:00:00.000 1
3 2014-01-14 00:00:00.000 1
3 2014-01-15 00:00:00.000 1
4 2014-01-20 00:00:00.000 1
4 2014-01-21 00:00:00.000 1
4 2014-01-22 00:00:00.000 1
4 2014-01-23 00:00:00.000 0
4 2014-01-24 00:00:00.000 0
4 2014-01-25 00:00:00.000 0
4 2014-01-26 00:00:00.000 1
4 2014-01-27 00:00:00.000 1
4 2014-01-28 00:00:00.000 1
4 2014-01-29 00:00:00.000 1
4 2014-01-30 00:00:00.000 1
(21 row(s) affected)
venue_id the_date
----------- -----------------------
4 2014-01-20 00:00:00.000
4 2014-01-21 00:00:00.000
4 2014-01-22 00:00:00.000
4 2014-01-23 00:00:00.000
4 2014-01-24 00:00:00.000
4 2014-01-25 00:00:00.000
4 2014-01-26 00:00:00.000
4 2014-01-27 00:00:00.000
4 2014-01-28 00:00:00.000
4 2014-01-29 00:00:00.000
4 2014-01-30 00:00:00.000
(11 row(s) affected)
venue_id the_date t_venueuser_venue_id
----------- ----------------------- --------------------
4 2014-01-20 00:00:00.000 NULL
4 2014-01-21 00:00:00.000 NULL
4 2014-01-22 00:00:00.000 NULL
4 2014-01-23 00:00:00.000 4
4 2014-01-24 00:00:00.000 4
4 2014-01-25 00:00:00.000 4
4 2014-01-26 00:00:00.000 NULL
4 2014-01-27 00:00:00.000 NULL
4 2014-01-28 00:00:00.000 NULL
4 2014-01-29 00:00:00.000 NULL
4 2014-01-30 00:00:00.000 NULL
(11 row(s) affected)