Sql 查询以反映数据中的实际重大变化
给定一个包含员工状态和生效日期的表,如何仅检索反映状态更改的数据 例如,给定以下结构:Sql 查询以反映数据中的实际重大变化,sql,sql-server,sql-server-2005,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',
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上的一次是无关紧要的,因为状态与之前的日期没有变化。还要注意,employee 2只列出了一次,因为尽管有三条记录,但他的状态从未改变。每次更改只显示最早的日期。经过进一步的试验,看起来这会满足我的要求
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
;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
通过进一步的实验,看起来这会满足我的要求
;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
你可以用光标
您需要两组变量:@PreviousRecord和@CurrentRecord
为按employeeid和日期排序的表声明光标
将光标中的第一条记录提取到@PreviousRecord变量中-根据您的要求将其注册为重大更改或不将记录写入临时表
然后设置一个循环:
将下一条记录提取到@CurrentRecord变量中
将其与以前的记录进行比较,如果它符合您对重大更改的要求,则将其写入临时表
将@CurrentRecord值移动到@PreviousRecord变量中
我想知道CTE方法是否更有效您可以使用光标
您需要两组变量:@PreviousRecord和@CurrentRecord
为按employeeid和日期排序的表声明光标
将光标中的第一条记录提取到@PreviousRecord变量中-根据您的要求将其注册为重大更改或不将记录写入临时表
然后设置一个循环:
将下一条记录提取到@CurrentRecord变量中
将其与以前的记录进行比较,如果它符合您对重大更改的要求,则将其写入临时表
将@CurrentRecord值移动到@PreviousRecord变量中
我很想知道CTE方法是否更有效或者,您可以在ON子句中添加和t2.STATUS_CODE=t1.STATUS_CODE,并将WHERE子句更改为类似于WHERE t1.EMPLOYEE_ID为NULL的形式。@AndriyM说得好,我喜欢读起来更好的方式,谢谢。更新。或者,您可以将AND t2.STATUS\U CODE=t1.STATUS\U CODE添加到ON子句中,并将WHERE子句更改为类似WHERE t1.EMPLOYEE\U ID为NULL的内容。@AndriyM说得好,我喜欢这样读起来更好,谢谢。更新。