查询以反映数据的实际重大变化

时间:2012-03-21 04:21:35

标签: sql sql-server sql-server-2005

如果有一个包含员工状态和生效日期的表格,我如何只检索反映状态变化的数据?

例如,给定以下结构:

DECLARE @STATUSES TABLE(
  EMPLOYEE_ID INT NOT NULL,
  EFFECTIVE_DATE DATE NOT NULL,
  STATUS_CODE CHAR(1) NOT NULL
)
INSERT @STATUSES VALUES (1, '2012-01-01', 'A')
INSERT @STATUSES VALUES (1, '2012-02-28', 'A')
INSERT @STATUSES VALUES (1, '2012-03-01', 'T')
INSERT @STATUSES VALUES (2, '2012-01-01', 'A')
INSERT @STATUSES VALUES (2, '2012-02-14', 'A')
INSERT @STATUSES VALUES (2, '2012-03-10', 'A')
INSERT @STATUSES VALUES (3, '2012-02-01', 'A')
INSERT @STATUSES VALUES (3, '2012-03-17', 'A')
INSERT @STATUSES VALUES (3, '2012-03-18', 'T')
INSERT @STATUSES VALUES (3, '2012-04-01', 'A')
INSERT @STATUSES VALUES (4, '2012-03-01', 'A')

可以使用什么查询来产生以下内容?

EMPLOYEE_ID     EFFECTIVE_DATE      STATUS_CODE
1               2012-01-01          A
1               2012-03-01          T
2               2012-01-01          A
3               2012-02-01          A
3               2012-03-18          T
3               2012-04-01          A
4               2012-03-01          A

换句话说,如果存在具有较早生效日期的记录,我想省略那些具有与之前相同的员工ID和状态代码的记录。请注意,员工1仅列出两次,因为状态只有两个实际变化 - 2012-02-28中的变更无关紧要,因为状态从较早的日期没有变化。另请注意,员工2只列出一次,因为他的状态从未改变,尽管有三条记录。每次更改只显示最早的日期。

3 个答案:

答案 0 :(得分:1)

通过一些进一步的实验,看起来这将做我想要的。

;WITH cte
     AS (SELECT ROW_NUMBER() OVER (PARTITION BY EMPLOYEE_ID ORDER BY EFFECTIVE_DATE) AS rownum
                ,EMPLOYEE_ID
                ,EFFECTIVE_DATE
                ,STATUS_CODE
         FROM   @STATUSES)
SELECT t2.EMPLOYEE_ID
       ,t2.EFFECTIVE_DATE
       ,t2.STATUS_CODE
FROM   cte t2
       LEFT JOIN cte t1
         ON t2.EMPLOYEE_ID = t1.EMPLOYEE_ID
            AND t2.STATUS_CODE = t1.STATUS_CODE
            AND t2.rownum = t1.rownum + 1
WHERE  t1.EMPLOYEE_ID IS NULL

答案 1 :(得分:0)

SELECT
  EMPLOYEE_ID, MIN(EFFECTIVE_DATE) AS EFFECTIVE_DATE, STATUS_CODE
FROM
    (
    SELECT
      T1.EMPLOYEE_ID, T1.EFFECTIVE_DATE, T1.STATUS_CODE,
      MAX(T2.EFFECTIVE_DATE) AS MOST_RECENT_PREVIOUS_STATUS_DATE
    FROM
      @STATUSES T1
        LEFT JOIN
      @STATUSES T2
        ON
        T1.EMPLOYEE_ID = T2.EMPLOYEE_ID
          AND
        T1.EFFECTIVE_DATE > T2.EFFECTIVE_DATE
          AND
        T1.STATUS_CODE <> T2.STATUS_CODE
    GROUP BY
      T1.EMPLOYEE_ID, T1.EFFECTIVE_DATE, T1.STATUS_CODE
    ) SubQuery
GROUP BY
  EMPLOYEE_ID, STATUS_CODE, MOST_RECENT_PREVIOUS_STATUS_DATE

答案 2 :(得分:0)

您可以使用游标

您需要两组变量:@PreviousRecord和@CurrentRecord

声明按employeeid和date

排序的表的游标

将光标中的第一条记录提取到@PreviousRecord变量中 - 根据您的要求将此注册为重要更改(将记录写入临时表)

然后设置一个循环:
 获取@CurrentRecord变量的下一条记录  将其与之前的记录进行比较,如果符合您对重大变更的要求,请将其写入临时表  将@CurrentRecord值移动到@PreviousRecord变量

我有兴趣知道CTE方法是否更有效