2013-08-19 46 views
0

我有一张表格,其中包含一个员工的时间戳记操作记录。每个记录都有一个部门和一个工作头衔。现在我想提取员工更改部门和/或工作职位时发生的更改。使用SQL语句将日志数据汇总到更改历史记录中

我使用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语句来完成吗?

回答

2

正如戈登·利诺夫说,这个问题是很容易当你有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 
+0

@ AlexanderFedorenko谢谢,修正了 –

+0

在指定员工后,我最终得到了这个解决方案: select t1.UserName,t1.ClosingTimestamp,t1.CurrentDepartmentName,t1.Cur从IssueView rentWorkPeriodEnd 为t1 外应用(从IssueView 选择顶部1 T2。* 为t2 其中t2.ClosingTimestamp t1.CurrentDepartmentName或 t2.CurrentWorktitleName <> t1.CurrentWorktitleName)和 t1.EmployeeSsn = 'xxx' 的 – MarkusPolus

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 
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