在SQL中删除无效的重复行

时间:2012-08-07 05:41:59

标签: asp.net sql sql-server-2005

我有一个表格,可以根据用户名通过Time Machine存储员工的登记时间。如果员工多次打孔,那么他的签到记录会有多个记录,这两个记录之间只有几秒钟的时差。显然只有第一条记录才有效。所有其他条目都无效,必须从表中删除。如果我可以选择当前日期的员工的所有签到记录,我该怎么办?

数据库中的数据如下。

Username               Checktime                       CheckType
 HRA001            7/29/2012 8:16:44 AM                Check-In
 HRA001            7/29/2012 8:16:46 AM                Check-In
 HRA001            7/29/2012 8:16:50 AM                Check-In 
 HRA001            7/29/2012 8:16:53 AM                Check-In 

8 个答案:

答案 0 :(得分:1)

试试这个:

 ;WITH users_CTE as (
 select rank() over (partition by Username order by Checktime) as rnk from users
 )

 DELETE FROM users_CTE where rnk <> 1

- 对于您的第二个要求,请尝试此查询

 ;WITH users_CTE as (
 select *,rank() over (partition by Username order by Checktime) as rnk from users
 )
,CTE2 as (select Username,MIN(CheckTime) as minTime,DATEADD(mi,1,MIN(CheckTime)) as maxTime from users_CTE 
 group by Username)



delete from users where Checktime in(
select c1.Checktime from users_CTE c1 left join CTE2 c2
on c1.Checktime > c2.minTime and c1.Checktime <= c2.maxTime
where c2.Username is not null and c1.Username in(

select c1.Username from users_CTE c1 left join CTE2 c2
on c1.Checktime > c2.minTime and c1.Checktime <= c2.maxTime
group by c1.Username,c2.Username 
having COUNT(*) > 1))

- 对于您更改的要求请查看下面的查询

alter table users add flag varchar(2)

;WITH users_CTE as (
 select *,rank() over (partition by Username order by Checktime) as rnk from users
 )
,CTE2 as (select Username,MIN(CheckTime) as minTime,DATEADD(mi,1,MIN(CheckTime)) as maxTime from users_CTE 
 group by Username)


update u SET u.flag = 'd' from users_CTE u inner join (
select c1.Checktime from users_CTE c1 left join CTE2 c2
on c1.Checktime > c2.minTime and c1.Checktime <= c2.maxTime
where c2.Username is not null and c1.Username in(

select c1.Username from users_CTE c1 left join CTE2 c2
on c1.Checktime > c2.minTime and c1.Checktime <= c2.maxTime
group by c1.Username,c2.Username 
having COUNT(*) > 1)) a
on u.Checktime=a.Checktime

- 使用DeletFlag检查最新查询

;WITH users_CTE as 
(
 select *,row_number() over (partition by Username order by Checktime) as row from users
)
,CTE as(
select row,Username,Checktime,CheckType,0 as totalSeconds,'N' as Delflag from users_CTE where row=1 
union all
select t.row,t.Username,t.Checktime,t.CheckType,CASE WHEN (c.totalSeconds + DATEDIFF(SECOND,c.Checktime,t.Checktime))  >= 60 then 0 else (c.totalSeconds + DATEDIFF(SECOND,c.Checktime,t.Checktime)) end as totalSeconds,
CASE WHEN (c.totalSeconds + DATEDIFF(SECOND,c.Checktime,t.Checktime))  >= 60 then 'N' else 'Y' end as Delflag
--CASE WHEN c.totalSeconds <= 60  then 'Y' else 'N' end as Delflag
from users_CTE t inner join CTE c
on t.row=c.row+1
)

select Username,Checktime,CheckType,Delflag from CTE

答案 1 :(得分:0)

为什么不在将签入插入db之前验证签入。如果此用户存在任何签到,则在此日期与该日期之间,则不执行任何其他操作

答案 2 :(得分:0)

您应该能够按时间顺序排序所有记录,从每位员工的上一次减去最新时间,如果结果小于某个阈值,则删除最近时间的行。

答案 3 :(得分:0)

您可以按签入时间尝试按RANK记录,然后删除RANK大于1的每一位员工的所有记录。

答案 4 :(得分:0)

尝试此查询:从员工中删除employee.checkin(从员工中选择checkin(checkin)&gt; 1);

答案 5 :(得分:0)

答案 6 :(得分:0)

DELETE FROM timesheet 
WHERE timesheetRecordId <>(
                SELECT TOP 1 timesheetRecordId from timesheet  
                WHERE checkInDate=todaysDate AND employeeId=empId ORDER BY checkInTime ASC
               ) 
AND checkInDate=today's date AND empolyeeId=empId;

答案 7 :(得分:0)

我认为您不能在同一语句的子查询中从Delete语句指定目标表。所以你不能用一个Delete语句来做。

您可以做的是编写存储过程。在您的存储过程中,您应该创建一个包含此查询返回的PK的临时表:

select cht.pkey 
  from CheckTimeTable as cht
  where exists ( select pkey
                   from CheckTimeTable 
                   where username = cht.userName
                     and checkType = 'check-IN'
                     and Checktime >= subtime(cht.Checktime, '0 0:0:15.000000') 
                     and Checktime < cht.Checktime);

然后写另一个语句从原始表CheckTimeTable中删除这些PK。

请注意,上面的查询是针对MySQL的,因此您需要找到从DBMS的时间戳中减去15秒的方法。在MySQL中,它是这样做的:

subtime(cht.Checktime, '0 0:0:15.000000')

此查询将返回具有另一个CheckTime记录的CheckTime记录,该记录来自同一用户,类型为Check-In,并且比其自己的检查时间早15秒。