簡體   English   中英

刪除時間戳列不同的SQL Server中單個表中的行

[英]Delete rows in single table in SQL Server where timestamp column differs

我有一張員工時鍾打卡表,看起來像這樣:

| EmployeeID | PunchDate  | PunchTime | PunchType | Sequence |
|------------|------------|-----------|-----------|----------|
|       5386 | 12/27/2016 | 03:57:42  | On Duty   |      552 |
|       5386 | 12/27/2016 | 09:30:00  | Off Duty  |      563 |
|       5386 | 12/27/2016 | 010:02:00 | On Duty   |      564 |
|       5386 | 12/27/2016 | 12:10:00  | Off Duty  |      570 |
|       5386 | 12/27/2016 | 12:22:00  | On Duty   |      571 |
|       5386 | 12/27/2016 | 05:13:32  | Off Duty  |      578 |  

我需要做的是刪除任何值班時間隨后的 值班時間之間的分鍾差小於25分鍾的行。 在上面的示例中,我想刪除序列570和571。

我已經從其他表拉動所有退出值班拳和使用此查詢拉都跟隨一名下班沖拳職責創建此表:

SELECT *  FROM [dbo].[Punches]
INSERT INTO [dbo].[UpdatePunches (EmployeeID,PunchDate,PunchTime,PunchType,Sequence)
SELECT *  FROM [dbo].[Punches]
WHERE Sequence IN (
SELECT Sequence + 1
FROM [dbo].[Punches]
WHERE PunchType LIKE 'Off Duty%') AND
PunchType LIKE 'On Duty%'   

我一直在嘗試將某種DATEDIFF查詢添加到此代碼中,並將其作為除掉這些錯誤的一個單獨步驟,但是沒有任何運氣。 我不能使用特定的序列號,因為每次打孔時這些序列號都會改變。

我正在使用SQL Server 2008。

任何建議將不勝感激。

您可以根據打孔日期和打孔時間為每個員工分配行號,並根據日期和時間的升序將每一行與下一行連接起來。

此后,獲取相差少於25分鍾的那些行的行號,最后刪除這些行。

with rownums as 
(select t.*,row_number() over(partition by employeeid 
                              order by cast(punchdate +' '+punchtime as datetime) ) as rn
 from t)
,rownums_to_delete as 
(
 select r1.rn,r1.employeeid
 from rownums r1
 join rownums r2 on r1.employeeid=r2.employeeid and r1.rn=r2.rn+1
 where dateadd(minute,25,cast(r2.punchdate +' '+r2.punchtime as datetime)) > cast(r1.punchdate +' '+r1.punchtime as datetime)
 and r1.punchtype <> r2.punchtype
 union all
 select r2.rn, r2.employeeid
 from rownums r1
 join rownums r2 on r1.employeeid=r2.employeeid and r1.rn=r2.rn+1
 where dateadd(minute,25,cast(r2.punchdate +' '+r2.punchtime as datetime)) > cast(r1.punchdate +' '+r1.punchtime as datetime)
 and r1.punchtype <> r2.punchtype
)
delete r
from rownums_to_delete rd
join rownums r on rd.employeeid=r.employeeid and r.rn=rd.rn

Sample Demo

如果日期和時間列不是varchar而是實際datetime數據類型, punchdate+punchtime在查詢中使用punchdate+punchtime

編輯:更簡單的查詢版本是

with todelete as (
select t1.employeeid,cast(t2.punchdate+' '+t2.punchtime as datetime) as punchtime,
t2.punchtype,t2.sequence,
cast(t1.punchdate+' '+t1.punchtime as datetime) next_punchtime, 
t1.punchtype as next_punchtype,t1.sequence as next_sequence
from t t1
join t t2 on t1.employeeid=t2.employeeid 
and cast(t2.punchdate+' '+t2.punchtime as datetime) between dateadd(minute,-25,cast(t1.punchdate+' '+t1.punchtime as datetime)) and cast(t1.punchdate+' '+t1.punchtime as datetime) 
where t2.punchtype <> t1.punchtype
    )
delete t
from t 
join todelete td on t.employeeid = td.employeeid 
and cast(t.punchdate+' '+t.punchtime as datetime) in (td.punchtime,td.next_punchtime)
;

SQL Server具有稱為可更新CTE的出色功能。 使用lead()lag() ,您可以完全執行所需的操作。 以下假設日期實際上存儲為datetime -這只是為了方便將日期和時間加在一起(您也可以顯式使用轉換):

with todelete as (
      select tcp.*,
             (punchdate + punchtime) as punchdatetime.
             lead(punchtype) over (partition by employeeid order by punchdate, punchtime) as next_punchtype,
             lag(punchtype) over (partition by employeeid order by punchdate, punchtime) as prev_punchtype,
             lead(punchdate + punchtime) over (partition by employeeid order by punchdate, punchtime) as next_punchdatetime,
             lag(punchdate + punchtime) over (partition by employeeid order by punchdate, punchtime) as prev_punchdatetime
      from timeclockpunches tcp
     )
delete from todelete
    where (punchtype = 'Off Duty' and
           next_punchtype = 'On Duty' and
           punchdatetime > dateadd(minute, -25, next_punchdatetime)
          ) or
          (punchtype = 'On Duty' and
           prev_punchtype = 'Off Duty' and
           prev_punchdatetime > dateadd(minute, -25, punchdatetime)
          );

編輯:

在SQL Server 2008中,您可以使用相同的想法,只是效率不高:

delete t
    from t outer apply
         (select top 1 tprev.*
          from t tprev
          where tprev.employeeid = t.employeeid and
                (tprev.punchdate < t.punchdate or
                 (tprev.punchdate = t.punchdate and tprev.punchtime < t.punchtime)
                )
          order by tprev.punchdate desc, tprev.punchtime desc
         ) tprev outer apply
         (select top 1 tnext.*
          from t tnext
          where tnext.employeeid = t.employeeid and
                (t.punchdate < tnext.punchdate or
                 (t.punchdate = tnext.punchdate and t.punchtime < tnext.punchtime)
                )
          order by tnext.punchdate desc, tnext.punchtime desc
         ) tnext
where (t.punchtype = 'Off Duty' and
       tnext.punchtype = 'On Duty' and
       t.punchdatetime > dateadd(minute, -25, tnext.punchdatetime)
      ) or
      (t.punchtype = 'On Duty' and
       tprev.punchtype = 'Off Duty' and
       tprev.punchdatetime > dateadd(minute, -25, t.punchdatetime)
      );

也許像這樣容易被擊中。這只是使用子查詢來查找下一個“值班”打卡機,並將其在主查詢中與“值班”打卡機進行比較。

          Delete
          FROM [dbo].[Punches] p
          where p.PunchTime >=
          dateadd(minute, -25, isnull (
   (select top 1 p2.PunchTime from [dbo].[Punches] p2 where 
   p2.EmployeeID=p.EmployeeID and p2.PunchType='On Duty' 
   and p1.Sequence < p2.Sequence and p2.PunchDate=p.PunchDate
   order by p2.Sequence asc)
   ),'2500-01-01')
          and p.PunchType='Off Duty'

您可以從CTE中的日期和時間字段創建DateTime,然后在下班時間之后查找下一個下班時間,如下所示:

;
WITH OnDutyDateTime AS
(
    SELECT 
    EmployeeID,
    Sequence,
    DutyDateTime = DATEADD(ms, DATEDIFF(ms, '00:00:00', PunchTime), CONVERT(DATETIME, PunchDate)) 
    FROM
    #TempEmployeeData 
    where PunchType = 'On Duty'
),
OffDutyDateTime As
(
    SELECT 
    EmployeeID,
    Sequence,
    DutyDateTime = DATEADD(ms, DATEDIFF(ms, '00:00:00', PunchTime), CONVERT(DATETIME, PunchDate)) 
    FROM
    #TempEmployeeData 
    where PunchType = 'Off Duty'
)

SELECT 
    OffDutyDateTime = DutyDateTime,
    OnDutyDateTime = (SELECT TOP 1 DutyDateTime FROM OnDutyDateTime WHERE EmployeeID = A.EmployeeID AND Sequence > A.Sequence ORDER BY Sequence ASC ),
    DiffInMinutes = DATEDIFF(minute,DutyDateTime,(SELECT TOP 1 DutyDateTime FROM OnDutyDateTime WHERE EmployeeID = A.EmployeeID AND Sequence > A.Sequence ORDER BY Sequence ASC ))

FROM
OffDutyDateTime A


OffDutyDateTime         OnDutyDateTime          DiffInMinutes
----------------------- ----------------------- -------------
2016-12-27 09:30:00.000 2016-12-27 10:02:00.000 32
2016-12-27 12:10:00.000 2016-12-27 12:22:00.000 12
2016-12-28 05:13:32.000 NULL                    NULL

(受影響的3行)

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM