2016-06-24 55 views
2

我在SQL Server中有一個表,允許用戶更改員工詳細信息。每次將新記錄放入EMPLOYEE_HIST表中時。只有EMP_ID爲員工保持不變,所有其他細節都可以修改。選擇員工詳細信息中的更改

此外,還有一個SEQ_NO列,它維護所做的條目序列。

EMPLOYEE_HIST

SEQ_NO EMP_ID SOME_VAL1 SOME_VAL2 
1  E1  V11   V21  (initial value of this employee) 
2  E2  V12   V22  (initial value of this employee) 
3  E3  V13   V23  (initial value of this employee) 
4  E2  V00   V22 
5  E1  V01   V21 
6  E2  V02   V22 
7  E4  V00   V00  (initial value of this employee) 

我想要一個查詢,這將給我的變化,以特定僱員的,像

EMP_ID SOME_VAL1_OLD SOME_VAL1_NEW SOME_VAL2_OLD SOME_VAL2_NEW 
E1  V11    V01    V21   V21 
E2  V12    V00    V22   V22 
E2  V00    V02    V22   V22 

UPDATE 另外員工詳細信息可以由用戶進行修改n次數,對於每次更改,結果集中應存在一行。 請幫忙。

編輯: 我終於用了LAG函數解決了。它會這樣工作:

SELECT *,ROW_NUMBER() OVER(PARTITION BY EMP_ID,CHANGE_NO ORDER BY EMP_ID,CHANGE_NO,SEQ_NO) 
FROM(
SELECT * FROM EMPLOYEE_HIST(SELECT LAG(SOME_VAL1) 
OVER(PARTITION BY EMP_ID ORDER BY EMP_ID,SEQ_NO) AS OLD_VAL, SOME_VAL1 AS NEW_VAL, '1' AS CHANGE_NO) T 
WHERE OLD_VAL<>NEW_VAL UNION ALL 
SELECT * FROM EMPLOYEE_HIST(SELECT LAG(SOME_VAL1) OVER(PARTITION BY EMP_ID ORDER BY EMP_ID,SEQ_NO) AS OLD_VAL, SOME_VAL2 AS NEW_VAL, '2' AS CHANGE_NO) T 
WHERE OLD_VAL<>NEW_VAL) TEMP 

但是,在包含300萬條記錄的表上獲取總共500行的性能非常慢。請提出一些建議,以改善排序成本

+0

hi @Ajinkya Deshmukh,你在EMPLOYEE_HIST表中有修改日期列嗎? – user3583912

+0

是的,有last_update_time,後面的記錄也有更高的序列號。 –

+1

您使用的是哪個版本的SQL服務器? – Kateract

回答

0

您可以使用CTE通過EMP_ID獲取分區的行號。然後在行號被偏移1處加入。

;WITH PartitionedRows 
AS 
(
    SELECT ROW_NUMBER() OVER(PARTITION BY EMP_ID ORDER BY SEQ_NO) AS RowID, EMP_ID, SOME_VAL1,SOME_VAL2 
    FROM EMPLOYEE_HIST 
) 
SELECT a.EMP_ID,b.SOME_VAL1 AS SOME_VAL1_OLD,a.SOME_VAL1 AS SOME_VAL1_NEW,b.SOME_VAL2 AS SOME_VAL2_OLD,a.SOME_VAL2 AS SOME_VAL2_NEW 
FROM PartitionedRows a 
LEFT JOIN PartitionedRows b ON a.EMP_ID = b.EMP_ID AND a.RowID = (b.RowID + 1) 
WHERE b.RowID IS NOT NULL 
0

用不同的數據模型可能會更好。您可以擁有包含相同數據結構的表EMPLOYEE_HIST_OLD。這將允許您歸檔以前的數據(即使使用時間戳和/或序列號),保持EMPLOYEE_HIST表的大小更小,並且不會定期引用數據等。這將允許基本的聯接語句在兩張桌子之間。

然後我會建議您使用EMPLOYEE_HIST_OLD記錄的時間戳來查找最近的修改,然後將這些記錄加回到當前記錄。這隻會向您顯示更改的記錄。如果您願意,您可以限制EMPLOYEE_HIST_OLD上的查詢以簡單地返回一條記錄(最新)。 SQL query to get most recent row for each instance of a given key

如果您必須保持在同一個EMPLOYEE_HIST表中,並且使用序號方法,則可能希望使用count()來查找特定Employee ID的更改記錄並返回按序號ORDERED的值。您也可以將查詢限制爲count> 1的員工。不過,您可以在表中垂直查看數據。要將這些值解析爲單獨的列(如VAR1_OLD和VAR1),基本上只會要求您只讀取最後兩個值,並將兩個值中的一個記錄刪除。在嘗試水平查看數據時,您會失去所有更改的可見性。可能會有不止一次的歷史變化。要水平查看記錄,需要在查詢返回數據之後,在SQL之外執行一些數組操作。

有關統計信息: SQL query for finding records where count > 1

1

您可以使用CTE與窗口的功能,如果你正在使用2008或更高版本:

;WITH r AS (
SELECT RANK() OVER (PARTITION BY EMP_ID ORDER BY SEQ_NO DESC) [rank] 
    , EMP_ID 
    , SOME_VAL1 
    , SOME_VAL2 
FROM EMPLOYEE_HIST 
) 
SELECT e.EMP_ID 
    , s2.SOME_VAL1 [SOME_VAL1_OLD] 
    , s1.SOME_VAL1 [SOME_VAL1_NEW] 
    , s2.SOME_VAL2 [SOME_VAL2_OLD] 
    , s1.SOME_VAL2 [SOME_VAL2_NEW] 
FROM (SELECT DISTINCT EMP_ID FROM EMPLOYEE_HIST) AS e 
LEFT JOIN r AS s1 ON e.EMP_ID = s1.EMP_ID and s1.rank = 1 --the last change 
LEFT JOIN r AS s2 ON e.EMP_ID = s2.EMP_ID and s2.rank = 2 --the second to last change 

如果你希望所有的變化,而不僅僅是那麼你應該可以這樣做:

;WITH r AS (
SELECT RANK() OVER (PARTITION BY EMP_ID ORDER BY SEQ_NO DESC) [rank] 
    , EMP_ID 
    , SOME_VAL1 
    , SOME_VAL2 
FROM EMPLOYEE_HIST 
) 
SELECT e.EMP_ID 
    , s2.SOME_VAL1 [SOME_VAL1_OLD] 
    , s1.SOME_VAL1 [SOME_VAL1_NEW] 
    , s2.SOME_VAL2 [SOME_VAL2_OLD] 
    , s1.SOME_VAL2 [SOME_VAL2_NEW] 
FROM (SELECT DISTINCT EMP_ID FROM EMPLOYEE_HIST) AS e 
LEFT JOIN (r AS s1 --the change 
    INNER JOIN r AS s2 ON s1.EMP_ID = s2.EMP_ID and s2.rank = s1.rank + 1) --previous value 
ON e.EMP_ID = s1.EMP_ID 

這應該枚舉所有更改,直到它遇到原始的val UE。

+0

這是相當有用的,但我不想比較排名2和排名1.內容是比較排名1和2,2和3,3和4等等每個EMP_ID。 –

+0

@AjinkyaDeshmukh我更新了第二部分的答案,並稍微改了一些名字,以使它們更加一致和易於理解,讓我知道這是否有助於您 – Kateract

相關問題