我有一张格式如下的表:
ID ID1 ID2 DATE
1 1 1 2018-03-01
2 1 1 2018-03-02
3 1 1 2018-03-05
4 1 1 2018-03-06
5 1 1 2018-03-07
6 2 2 2018-03-05
7 2 2 2018-03-05
8 2 2 2018-03-06
9 2 2 2018-03-07
10 2 2 2018-03-08
从这张表中我必须得到ID1
和ID2
在该列中相同的所有记录,其中DATE
是连续5个工作日(连续5个日期,忽略星期六/星期日缺少日期;忽略假期。)
我真的不知道如何实现这一目标。我做了搜索,但找不到任何帮助我的东西。所以我的问题是,我如何实现以下输出?
ID ID1 ID2 DATE
1 1 1 2018-03-01
2 1 1 2018-03-02
3 1 1 2018-03-05
4 1 1 2018-03-06
5 1 1 2018-03-07
答案 0 :(得分:1)
假设您没有重复项并且工作日仅 ,那么这个特殊情况就有一个简洁的解决方案。我们可以确定前面4行的日期。整整一周,提前4天或提前6天:
select t.*
from (select t.*, lead(dat, 4) over (order by id2, dat) as dat_4
from t
) t
where datediff(day, dat, dat_4) in (4, 6);
这恰好起作用,因为你正在寻找一个完整的一周。
Here是SQL小提琴。
答案 1 :(得分:1)
select t.* from
(select id1,id2,count(distinct dat) count from t
group by id1,id2
having count(distinct dat)=5) t1 right join
t
on t.id1=t1.id1 and t.id2=t1.id2
where count=5
检查一下 -
两周的日期,有效期为10天 http://sqlfiddle.com/#!18/76556/1
两周的日期,有10个非独特日期 http://sqlfiddle.com/#!18/b4299/1
和
两周的日期少于10但独特 http://sqlfiddle.com/#!18/f16cb/1
答案 2 :(得分:1)
这个查询非常详细,没有LEAD或LAG,这是我午休时能做的最好的。考虑到时间,你可以改进它。
DECLARE @T TABLE
(
ID INT,
ID1 INT,
ID2 INT,
TheDate DATETIME
)
INSERT @T SELECT 1,1,1,'03/01/2018'
INSERT @T SELECT 2,1,1,'03/02/2018'
INSERT @T SELECT 3,1,1,'03/05/2018'
INSERT @T SELECT 4,1,1,'03/06/2018'
INSERT @T SELECT 5,1,1,'03/07/2018'
--INSERT @T SELECT 5,1,1,'03/09/2018'
INSERT @T SELECT 6,2,2,'03/02/2018'
INSERT @T SELECT 7,2,2,'03/05/2018'
INSERT @T SELECT 8,2,2,'03/05/2018'
--INSERT @T SELECT 9,2,2,'03/06/2018'
INSERT @T SELECT 10,2,2,'03/07/2018'
INSERT @T SELECT 11,2,2,'03/08/2018'
INSERT @T SELECT 12,2,2,'03/15/2018'
INSERT @T SELECT 13,1,1,'04/01/2018'
INSERT @T SELECT 14,1,1,'04/02/2018'
INSERT @T SELECT 15,1,1,'04/05/2018'
--SELECT * FROM @T
DECLARE @LowDate DATETIME = DATEADD(DAY,-1,(SELECT MIN(TheDate) FROM @T))
DECLARE @HighDate DATETIME = DATEADD(DAY,1,(SELECT MAX(TheDate) FROM @T))
DECLARE @DaysThreshold INT = 5
;
WITH Dates AS
(
SELECT DateValue=@LowDate
UNION ALL
SELECT DateValue + 1 FROM Dates
WHERE DateValue + 1 < @HighDate
),
Joined AS
(
SELECT * FROM Dates LEFT OUTER JOIN @T T ON T.TheDate=Dates.DateValue
),
Calculations AS
(
SELECT
ID=MAX(J1.ID),
J1.ID1,J1.ID2,
J1.TheDate,
LastDate=MAX(J2.TheDate),
LastDateWasWeekend = CASE WHEN ((DATEPART(DW,DATEADD(DAY,-1,J1.TheDate) ) + @@DATEFIRST) % 7) NOT IN (0, 1) THEN 0 ELSE 1 END,
Offset = DATEDIFF(DAY,MAX(J2.TheDate),J1.TheDate)
FROM
Joined J1
LEFT OUTER JOIN Joined J2 ON J2.ID1=J1.ID1 AND J2.ID2=J1.ID2 AND J2.TheDate<J1.TheDate
WHERE
NOT J1.ID IS NULL
GROUP BY J1.ID1,J1.ID2,J1.TheDate
)
,FindValid AS
(
SELECT
ID,ID1,ID2,TheDate,
IsValid=CASE
WHEN LastDate=TheDate THEN 0
WHEN LastDate IS NULL THEN 1
WHEN Offset=1 THEN 1
WHEN Offset>3 THEN 0
WHEN Offset<=3 THEN
LastDateWasWeekend
END
FROM
Calculations
UNION
SELECT DISTINCT ID=NULL,ID1,ID2, TheDate=@HighDate,IsValid=0 FROM @T
),
FindMax As
(
SELECT
This.ID,This.ID1,This.ID2,This.TheDate,MaxRange=MIN(Next.TheDate)
FROM
FindValid This
LEFT OUTER JOIN FindValid Next ON Next.ID2=This.ID2 AND Next.ID1=This.ID1 AND This.TheDate<Next.TheDate AND Next.IsValid=0
GROUP BY
This.ID,This.ID1,This.ID2,This.TheDate
),
FindMin AS
(
SELECT
This.ID,This.ID1,This.ID2,This.TheDate,This.MaxRange,MinRange=MIN(Next.TheDate)
FROM
FindMax This
LEFT OUTER JOIN FindMax Next ON Next.ID2=This.ID2 AND Next.ID1=This.ID1 AND This.TheDate<Next.MaxRange-- AND Next.IsValid=0 OR Next.TheDate IS NULL
GROUP BY
This.ID,This.ID1,This.ID2,This.TheDate,This.MaxRange
)
,Final AS
(
SELECT
ID1,ID2,MinRange,MaxRange,SequentialCount=COUNT(*)
FROM
FindMin
GROUP BY
ID1,ID2,MinRange,MaxRange
)
SELECT
T.ID,
T.ID1,
T.ID2,
T.TheDate
FROM @T T
INNER JOIN Final ON T.TheDate>= Final.MinRange AND T.TheDate < Final.MaxRange AND T.ID1=Final.ID1 AND T.ID2=Final.ID2
WHERE
SequentialCount>=@DaysThreshold
OPTION (MAXRECURSION 0)