我试图弄清楚如何编写查询某些记录并查找今天和 9999-12-31 之间的日期范围的查询。 我的数据如下:
ID |start_dt |end_dt |prc_or_disc_1
10412 |2018-07-17 00:00:00.000 |2018-07-20 00:00:00.000 |1050.000000
10413 |2018-07-23 00:00:00.000 |2018-07-26 00:00:00.000 |1040.000000
因此对于此数据,我希望查询返回:
2018-07-10 | 2018-07-16
2018-07-21 | 2018-07-22
2018-07-27 | 9999-12-31
我不太确定从哪里开始。这可能吗?
答案 0 :(得分:1)
select
CASE WHEN DATEDIFF(day, end_dt, ISNULL(LEAD(start_dt) over (order by ID), '99991231')) > 1 then end_dt +1 END as F1,
CASE WHEN DATEDIFF(day, end_dt, ISNULL(LEAD(start_dt) over (order by ID), '99991231')) > 1 then ISNULL(LEAD(start_dt) over (order by ID) - 1, '99991231') END as F2
from t
有效的SQLFiddle示例是-> Here
2008年版本
SELECT
X.end_dt + 1 as F1,
ISNULL(Y.start_dt-1, '99991231') as F2
FROM t X
LEFT JOIN (
SELECT
*
, (SELECT MAX(ID) FROM t WHERE ID < A.ID) as ID2
FROM t A) Y ON X.ID = Y.ID2
WHERE DATEDIFF(day, X.end_dt, ISNULL(Y.start_dt, '99991231')) > 1
有效的SQLFiddle示例是-> Here
答案 1 :(得分:1)
您可以使用MS SQL中的lag()函数来完成此操作(但是从2012年开始可用吗?)。
with myData as
(
select *,
lag(end_dt,1) over (order by start_dt) as lagEnd
from myTable),
myMax as
(
select Max(end_dt) as maxDate from myTable
)
select dateadd(d,1,lagEnd) as StartDate, dateadd(d, -1, start_dt) as EndDate
from myData
where lagEnd is not null and dateadd(d,1,lagEnd) < start_dt
union all
select dateAdd(d,1,maxDate) as StartDate, cast('99991231' as Datetime) as EndDate
from myMax
where maxDate < '99991231';
如果lag()在MS SQL 2008中不可用,则可以使用row_number()和加入来模拟它。
答案 2 :(得分:1)
http://sqlfiddle.com/#!18/65238/1
SELECT
*
FROM
(
SELECT
end_dt+1 AS start_dt,
LEAD(start_dt-1, 1, '9999-12-31')
OVER (ORDER BY start_dt)
AS end_dt
FROM
yourTable
)
gaps
WHERE
gaps.end_dt >= gaps.start_dt
但是,我会 强 ,敦促您使用“独占”结束日期。也就是说,范围是除end_dt
以外的所有内容。
这样,一天的范围变为'2018-07-09', '2018-07-10'
。
很明显,我的范围是一天,如果您从另一范围中减去一个范围,则可以得到一天。
此外,如果您更改为需要小时粒度或分钟粒度 ,则无需更改数据 。它只是工作。总是。可靠地。直观地。
如果您在网络上搜索,则会发现大量文档,从软件角度来看,为什么包容性开始和包容性结束是 非常 的好主意。 (然后,在上面的查询中,您可以删除不可靠的+1
和-1
。)
答案 3 :(得分:1)
这应该在2008年有效,它假定表中的范围不重叠。它还将消除当前行的end_date是下一行的开始日期的前一天的行。
with dtRanges as (
select start_dt, end_dt, row_number() over (order by start_dt) as rownum
from table1
)
select t2.end_dt + 1, coalesce(start_dt_next -1,'99991231')
FROM
( select dr1.start_dt, dr1.end_dt,dr2.start_dt as start_dt_next
from dtRanges dr1
left join dtRanges dr2 on dr2.rownum = dr1.rownum + 1
) t2
where
t2.end_dt + 1 <> coalesce(start_dt_next,'99991231')
答案 4 :(得分:0)
您可能想看看以下内容: http://sqlfiddle.com/#!18/3a224/1 您只需将开始范围编辑为今天,将结束范围编辑为9999-12-31。
答案 5 :(得分:0)
这可以解决您的问题,但如果有重叠,边缘情况等,请提供一些示例数据。
在结束日期之后的第一天和下一行的开始日期的第一天之前。
DECLARE @ TABLE (ID int, start_dt DATETIME, end_dt DATETIME, prc VARCHAR(100))
INSERT INTO @ (id, start_dt, end_dt, prc)
VALUES
(10410, '2018-07-09 00:00:00.00','2018-07-12 00:00:00.000','1025.000000'),
(10412, '2018-07-17 00:00:00.00','2018-07-20 00:00:00.000','1050.000000'),
(10413, '2018-07-23 00:00:00.00','2018-07-26 00:00:00.000','1040.000000')
SELECT DATEADD(DAY, 1, end_dt)
, DATEADD(DAY, -1, LEAD(start_dt, 1, '9999-12-31') OVER(ORDER BY id) )
FROM @
答案 6 :(得分:0)
可以使用窗口功能LEAD。
DATEDIFF和WHERE子句。
示例代码段:
declare @Table table (ID int, start_dt datetime, end_dt datetime, prc_or_disc_1 float);
insert into @Table (ID, start_dt, end_dt, prc_or_disc_1) values
(10410,'2018-07-09 00:00:00','2018-07-12 00:00:00',1025.0)
,(10412,'2018-07-17 00:00:00','2018-07-20 00:00:00',1050.0)
,(10413,'2018-07-23 00:00:00','2018-07-26 00:00:00',1040.0)
;
select
start_date,
coalesce(end_date, convert(date,'9999-12-31')) as end_date
from
(
select
convert(date, dateadd(day, 1, end_dt)) as start_date,
convert(date, dateadd(day, -1, lead(start_dt) over (order by ID))) as end_date
from @Table
) q
where coalesce(datediff(day, start_date, end_date), 9) >= 0
order by start_date;