我有一张表,其中包含员工的时间戳记行动记录。每条记录都有一个部门和一个工作头衔。现在,我想提取员工更改部门和/或工作头衔时发生的更改。
我正在使用SQL Server 2008。
假设我们的表保存了一个简单员工的记录,数据可能如下所示:
Time | Department | WorkTitle
t1 Dep1 Wt1 <---
t2 Dep1 Wt1
t3 Dep2 Wt2 <---
t4 Dep2 Wt2
t5 Dep1 Wt1 <---
t6 Dep3 Wt1 <---
t7 Dep3 Wt1
t8 Dep3 Wt1
我希望在员工出现在新部门和/或拥有新工作头衔时提取第一个实例。
在上述数据中,带箭头的记录应该是提取的记录,并且应该得到以下结果:
Time | Department | WorkTitle
t1 Dep1 Wt1
t3 Dep2 Wt2
t5 Dep1 Wt1
t6 Dep3 Wt1
请注意,在时间t1和t5出现相同的部门和工作标题,因此简单的GROUP BY子句不起作用。
我尝试了一些使用OVER / PARTITION的尝试,但这个查询的复杂性似乎超出了我的想法。
可以使用SQL语句完成吗?
答案 0 :(得分:3)
您真正需要的功能是lag()
,但直到SQL Server 2012才可用。在缺少的情况下,我更喜欢相关的子查询。
此方法检索上一次,然后将表重新加入表中,并进行比较以进行过滤:
select tprev.*
from (select t.*,
(select top 1 time
from t t2
where t.time < t2.time
order by time desc
) as prevtime
from t
) tprev join
t
on tprev.prevtime = t.time
where tprev.department <> t.department or
tprev.worktitle <> t.worktitle or
tprev.prevtime is null
答案 1 :(得分:2)
正如Gordon Linoff所说,当你有lag()功能时,这个问题非常容易。 SQL Server 2008没有它,因此我更倾向于使用outer apply解决它:
select t1.*
from t as t1
outer apply (
select top 1 t2.*
from t as t2
where t2.worktime < t1.worktime
order by t2.worktime desc
) as t2
where
t2.worktime is null or
t2.department <> t1.department or
t2.worktitle <> t1.worktitle
答案 2 :(得分:0)
您可以尝试这种非triangular join解决方案:
DECLARE @MyTable TABLE(
-- You should use appropiate data types for every column
[Time] VARCHAR(20) NOT NULL,
Department VARCHAR(20) NOT NULL,
WorkTitle VARCHAR(20) NOT NULL
);
INSERT INTO @MyTable ([Time],Department,WorkTitle)
SELECT 't1', 'Dep1', 'Wt1'
UNION ALL SELECT 't2', 'Dep1', 'Wt1'
UNION ALL SELECT 't3', 'Dep2', 'Wt2'
UNION ALL SELECT 't4', 'Dep2', 'Wt2'
UNION ALL SELECT 't5', 'Dep1', 'Wt1'
UNION ALL SELECT 't6', 'Dep3', 'Wt1'
UNION ALL SELECT 't7', 'Dep3', 'Wt1'
UNION ALL SELECT 't8', 'Dep3', 'Wt1';
DECLARE @ResultsWithRowNum TABLE
(
RowNum INT PRIMARY KEY,
[Time] VARCHAR(20) NOT NULL,
Department VARCHAR(20) NOT NULL,
WorkTitle VARCHAR(20) NOT NULL
);
INSERT @ResultsWithRowNum(RowNum,[Time],Department,WorkTitle)
SELECT ROW_NUMBER() OVER(ORDER BY x.[Time]) AS RowNum,x.[Time],x.Department,x.WorkTitle
FROM @MyTable x;
WITH RecursiveCTE
AS
(
SELECT crt.RowNum,
crt.[Time],
crt.Department,
crt.WorkTitle,
1 AS IsFirstRowNewGroup
FROM @ResultsWithRowNum crt
WHERE crt.RowNum=1
UNION ALL
SELECT crt.RowNum,
crt.[Time],
crt.Department,
crt.WorkTitle,
CASE WHEN prev.Department = crt.Department AND prev.WorkTitle = crt.WorkTitle THEN 0 ELSE 1 END
FROM @ResultsWithRowNum crt
INNER JOIN RecursiveCTE prev ON crt.RowNum = prev.RowNum + 1
)
SELECT *
FROM RecursiveCTE rec
WHERE rec.IsFirstRowNewGroup = 1
OPTION (MAXRECURSION 0);
结果:
RowNum Time Department WorkTitle IsFirstRowNewGroup
------ ---- ---------- --------- ------------------
1 t1 Dep1 Wt1 1
3 t3 Dep2 Wt2 1
5 t5 Dep1 Wt1 1
6 t6 Dep3 Wt1 1