0

我有一张表,其中包含员工的时间戳操作记录。每条记录都有一个部门和一个工作名称。现在我想提取当员工更改部门和/或工作头衔时发生了什么变化。

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

4

3 回答 3

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
于 2013-08-19T15:48:43.727 回答
2

正如 Gordon Linoff 所说,当你有lag()函数时,这个问题真的很容易。SQL Server 2008 没有它,所以我更喜欢用external 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
于 2013-08-19T16:06:46.343 回答
0

您可以尝试这种非三角形连接解决方​​案:

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
于 2013-08-19T16:47:42.663 回答