我要求连续三天从表中删除行(如果周末介于两者之间,则排除日期)
CREATE TABLE [dbo].[Test]
(
[Scanid] [bigint] NULL,
[Employeeid] [int] NULL,
[Datescanned] [datetime] NULL
)
INSERT INTO [dbo].[Test]([Scanid], [Employeeid], [Datescanned])
VALUES (108639, 3820, '2016-04-28 17:12:33.000'),
(108639, 3820, '2016-04-28 18:05:46.000'),
(108639, 3820, '2016-04-28 20:58:36.000'),
(999999, 3820, '2016-04-29 10:08:00.000'),
(999999, 3820, '2016-04-29 10:12:10.000'),
(777777, 3820, '2016-05-02 10:12:00.000'),
(111111, 3820, '2016-04-04 10:12:00.000'),
(33333, 3820, '2016-04-11 17:23:00.000'),
(987623, 3820, '2016-04-18 11:12:00.000'),
(1234, 3820, '2016-05-26 10:00:00.000'),
(5678, 3820, '2016-05-27 10:00:00.000'),
(8920, 3820, '2016-05-31 10:00:00.000')
输出:
Scanid Employeeid Datescanned
----------------------------------------
108639 3820 2016-04-28 17:12:33.000
108639 3820 2016-04-28 18:05:46.000
108639 3820 2016-04-28 20:58:36.000
999999 3820 2016-04-29 10:08:00.000
999999 3820 2016-04-29 10:12:10.000
777777 3820 2016-05-02 10:12:00.000
111111 3820 2016-04-04 10:12:00.000
33333 3820 2016-04-11 17:23:00.000
987623 3820 2016-04-18 11:12:00.000
1234 3820 2016-05-26 10:00:00.000
5678 3820 2016-05-27 10:00:00.000
8920 3820 2016-05-31 10:00:00.000
我们只能从日期扫描字段中取日期,然后在上面的示例中,我们应该删除连续3个日期的行,从2016-04-28'到' 2016-05-02' (2016-04-30和31是周末,所以我们可以忽略),并删除连续3个日期的行,从2016-05-26'到2016-05-31' (2016-05-29和30th是周末,所以我们可以忽略)。因此,只有结果应该显示2016-04-04,2016-04-11,2016-04-18之前的行,这些日期之前或之后都不会连续3天。
答案 0 :(得分:1)
以下是您想要的确切输出..
我可以在你的问题中看到一个错误,[即。从' 2016-05-26'删除连续3个日期的行到2016-05-31' ( 2016-05-29 和 30th 是周末,所以我们可以忽略)'],那些周末天数不正确..正确的日期是 2016-05-28 和 2016-05-29
DROP TABLE [TestDates]
GO
CREATE TABLE [dbo].[TestDates](
[Scanid] [bigint] NULL,
[Employeeid] [int] NULL,
[Datescanned] [datetime] NULL
)
INSERT INTO [dbo].[TestDates] ([Scanid] ,[Employeeid],[Datescanned])
VALUES (108639,3820,'2016-04-28 17:12:33.000'),(108639,3820,'2016-04-28 18:05:46.000'),
(108639,3820,'2016-04-28 20:58:36.000'),(999999,3820,'2016-04-29 10:08:00.000'),
(999999,3820,'2016-04-29 10:12:10.000'),(777777,3820,'2016-05-02 10:12:00.000'),
(111111,3820,'2016-04-04 10:12:00.000'),(33333,3820,'2016-04-11 17:23:00.000'),
(987623,3820,'2016-04-18 11:12:00.000'),(1234,3820,'2016-05-26 10:00:00.000'),
(5678,3820,'2016-05-27 10:00:00.00'), (8920, 3820, '2016-05-30 10:00:00.000')
GO
DROP TABLE #t
GO
SELECT DISTINCT Employeeid,CONVERT(date,Datescanned) Datescanned INTO #T
FROM [TestDates]
GO
;WITH cte_cnt
AS
(
SELECT Employeeid, MIN(Datescanned) AS FROM_DATE
,MAX(Datescanned) AS TO_DATE
, COUNT('A') AS DayDiff
FROM (
SELECT Employeeid,Datescanned,
ROW_NUMBER() OVER(ORDER BY Datescanned) AS ROW_NUMBER,
DATEDIFF(D, ROW_NUMBER() OVER(ORDER BY Datescanned)
,CASE WHEN DATENAME(dw, cast (Datescanned as datetime)-1) = 'Sunday' THEN DATEADD(DAY, -2, Datescanned) ELSE Datescanned END) AS Diff
FROM #t) AS dt
GROUP BY Employeeid, Diff )
DELETE t
--SELECT *
FROM cte_cnt c
JOIN [TestDates] t
ON c.Employeeid=t.Employeeid
WHERE CAST(t.Datescanned as DATE) BETWEEN c.FROM_DATE AND c.TO_DATE and c.DayDiff=3
GO
SELECT *
FROM [TestDates]
GO
答案 1 :(得分:0)
也许这个?:
delete from Test
where not exists (
select 1
from Test t2
where cast(t2.Datescanned as date)
between
dateadd(day,
case datepart(dayofweek, cast(Test.Datescanned as date))
when 1 then -4 when 2 then -4
else -2
end,
cast(Test.Datescanned as date)
)
and
dateadd(day,
case datepart(dayofweek, cast(Test.Datescanned as date))
when 4 then 4 when 5 then 4
else 2
end,
cast(Test.Datescanned as date)
)
)
答案 2 :(得分:0)
不考虑假期的解决方案是
SELECT
t.*
FROM (SELECT DISTINCT
CAST(t1.datescanned AS date) first_date,
CAST(t2.datescanned AS date) second_date,
CAST(t3.datescanned AS date) third_date
FROM test t1
JOIN test t2 --add a join condition for employeeid as well
ON DATEDIFF(dd, CAST(t1.datescanned AS date), CAST(t2.datescanned AS date)) = 1
OR (DATEPART(WEEKDAY, CAST(t2.datescanned AS date)) = 2
AND DATEDIFF(dd, CAST(t1.datescanned AS date), CAST(t2.datescanned AS date)) = 3)
JOIN test t3 --add a join condition for employeeid as well
ON DATEDIFF(dd, CAST(t2.datescanned AS date), CAST(t3.datescanned AS date)) = 1
OR (DATEPART(WEEKDAY, CAST(t3.datescanned AS date)) = 2
AND DATEDIFF(dd, CAST(t2.datescanned AS date), CAST(t3.datescanned AS date)) = 3)
) x
JOIN test t
ON CAST(t.datescanned AS date) = x.first_date
OR CAST(t.datescanned AS date) = x.second_date
OR CAST(t.datescanned AS date) = x.third_date
自我加入表格两次,每次都在
结果给出了需要删除的行。但需要注意的是,如果没有间隙,这将连续超过3天。在这种情况下,您需要解释是否要在第3天停止删除。
答案 3 :(得分:0)
以前的脚本很好。我会做一个改进,周末和假日检查,添加一个功能,并在选择语句中调用它。 这是一个你可以使用的简单函数(我假设你有一个名为Holiday的表,它保存每个州的所有假日日期)
Create FUNCTION [dbo].[IsHolidayOrWeekend]
(
@date DateTime,
@stateId int
)
RETURNS Bit
AS
BEGIN
declare @dayOfWeek VARCHAR(9);
set @dayOfWeek = DATEName(DW, @date);
IF(@dayOfWeek = 'Saturday' OR @dayOfWeek = 'Sunday')
RETURN 1;
ELSE
begin
set @date = cast(@date as date) -- Remove the time portion
RETURN IsNull((SELECT 1 from Holiday where StateId = @provinceId and HolidayDate = @date ), 0)
end;
END
答案 4 :(得分:0)
除了周末之外,我还有一个额外的要求,即igonre假期。我创建了Test_calendar表,删除了所有假日和周末,并将行号分配给活动天。然后这是我使用的代码。如果我们有数百万行,它可以工作,但可能不是很快。对我来说,数据很小,所以它将完成工作。如果您可以简化删除过程以使其快速,请告诉我。
SELECT distinct scanid as [badgeid] , Employeeid,CONVERT(date, Datescanned) as Datescanned,RN
into #test1
FROM [dbo].[Test] a
inner join Test_Calendar b
on CONVERT(date, a.Datescanned)=b.Cal_date
order by Datescanned asc
declare @min int
declare @max int
declare @i int
select @min=MIN(rn) from #test1
select @max=Max(rn) from #test1
while(@min<@max)
begin
select @i=COUNT(*) from #test1 where rn in(@min ,@min+1,@min+2)
if(@i=3)
select * from #test1 where rn in(@min ,@min+1,@min+2)
set @min=@min+1
end