数据看起来像
[Month] [Date]
---------------
201306 1
201306 2
201306 5
201306 6
201306 7
201307 1
201307 4
201307 6
201309 1
201309 2
如何按月找到所有缺失的日期?
以下是预期结果
[Month] [Date]
---------------
201306 3
201306 4
201307 2
201307 3
201307 5
答案 0 :(得分:2)
我认为这样做非常有效
declare @T table (yy int, dd int);
insert into @T values
(201306, 1)
, (201306, 2)
, (201306, 5)
, (201306, 6)
, (201306, 7)
, (201307, 1)
, (201307, 4)
, (201307, 6)
, (201309, 1)
, (201309, 2);
with cte as
( select yy, min(dd) + 1 as mn, max(dd) as mx
from @T
group by yy
having min(dd) + 1 < max(dd)
union all
select c.yy, c.mn + 1, c.mx
from cte c
where c.mn + 1 < c.mx
)
select yy, mn as dd
from cte
except
select yy, dd
from @T t
order by yy, mn;
yy dd
----------- -----------
201306 3
201306 4
201307 2
201307 3
201307 5
答案 1 :(得分:1)
您需要某种可能具有中间日期的lookup
表,并使用cross join
与left join
查找缺少的日期
首先 想法
;with cte as (
select min(date) mdate, max(date) mxdate from table
union all
select mdate+1 as mdate, mxdate
from cte c
where c.mdate < c.mxdate
)
select distinct t.Month, c.mdate
from table t cross join (select mdate from cte) c
left join table t1 on t1.month = t.Month and t1.date = c.mdate
where t1.date is null
第二次 思想
;with cte as (
select month, min(date) over (partition by month) mdate, max(date) over (partition by month) mxdate
from sample t union all
select month, mdate+1 as mdate, mxdate
from cte c
where c.month = month and c.mdate < c.mxdate
)
select c.month, c.mdate
from cte c left join sample t1
on t1.month = c.Month and t1.date = c.mdate
where t1.date is null
group by c.month, c.mdate
答案 2 :(得分:0)
考虑使用递归查询
with rndata as
(
select row_number() over (partition by mon order by d) rn, * from data
), rcte as
(
select mon, d, (select max(d) from data where data.mon = rndata.mon) max_d
from rndata where rn = 1
union all
select rcte.mon, rcte.d + 1, rcte.max_d
from rcte
where rcte.d + 1 < max_d
)
select mon, d
from rcte
where not exists (
select 1
from data
where rcte.mon = data.mon and
rcte.d = data.d
)
答案 3 :(得分:0)
考虑使用以下方法。
CREATE TABLE #Date([Month] int, [Date] int)
INSERT INTO #Date
VALUES(201306, 1)
,(201306, 2)
,(201306, 5)
,(201306, 6)
,(201306, 7)
,(201307, 1)
,(201307, 4)
,(201307, 6)
,(201309, 1)
,(201309, 2)
;WITH CTE AS
(
SELECT
*,LEAD([Date]) OVER(ORDER BY [Month],[Date]) AS NextDate
FROM #Date d
)
SELECT
d.[Month], m.Dt AS [Date]
FROM CTE d
CROSS APPLY( SELECT v.Dt
FROM
(VALUES(1),(2),(3),(4),(5),(6),(7),(8),(9),(10),(11)
,(11),(12),(13),(14),(15),(16),(17),(18),(19),(20)
,(21),(22),(23),(24),(25),(26),(27),(28),(29),(30),(31)
) AS v(Dt)
WHERE v.Dt > d.Date AND v.Dt < d.NextDate
) m
这种方法的唯一限制是,它无法找到在第一次约会之前的失踪天数。
答案 4 :(得分:0)
这是一个快速但仍然很简单的解决方案:
1)使用sys.sysobjects
作为计数表来获取每个月的所有日期
2)每个月的最小/最大范围,以保持范围内的间隙
3)加入计数和范围以获得每个月的预期日期,并将您的表格连接到数学现有日期
4)在WHERE
条件下过滤仅缺少日期
declare @T table ([month] int, [date] int);
insert into @T values
(201306, 1)
, (201306, 2)
, (201306, 5)
, (201306, 6)
, (201306, 7)
, (201307, 1)
, (201307, 4)
, (201307, 6)
, (201309, 1)
, (201309, 2);
with
n as (select top 31 ROW_NUMBER() over (order by id) n from sys.sysobjects),
r as (select [month], MIN([date]) dd1, MAX([date]) dd2 from @t group by [month])
select r.[month], n [date]
from r
join n on n between dd1 and dd2
left join @T t on n.N = t.[date] and r.[month] = t.[month]
where dd2<>dd1 and t.[date] is null
order by r.[month], n
答案 5 :(得分:-1)
你可以使用如下数字/ Tally表方法: 的 See live demo 强>
create table sample ([Month] int, [Date] int)
insert into sample values
(201306, 1)
,(201306, 2)
,(201306, 5)
,(201306, 6)
,(201306, 7)
,(201307, 1)
,(201307, 4)
,(201307, 6)
,(201309, 1)
,(201309, 2);
; with daysinmonth as
(
select * from
(
values
(1,31),(2,28),(3,31),(4,30),(5,31),(6,30),
(7,31),(8,31),(9,30),(10,31),(11,30),(12,31)
) v(m,d)
)
select [month], dd
from sample
cross apply
(
select top
(
select d from
daysinmonth
where m=cast( right(cast([Month] as varchar(6)),2) as int)
)
row_number() over ( order by (select null)) dd
from
sys.tables t1 cross join
sys.tables t2
) c
where [date]<>dd