2011-10-18 44 views
1

我有一個SQL Server 2008數據庫和歷史記錄表,用於在主表中記錄更改。我需要報告'rate'列的當前(最新)值,以及最近一次與當前值不同的前一個值。用於比較歷史記錄表中的列中的當前值和先前值的SQL查詢

因此,鑑於這樣的:

id | rate | uninteresting | updated_on | version 
-----+--------+---------------+--------------+---------- 
123 | 1.20 | foo   | 2010-10-18 | 1500 
456 | 2.10 | bar   | 2010-10-12 | 2123 
123 | 1.20 | baz   | 2010-10-10 | 1499 
123 | 1.10 | baz   | 2010-10-08 | 1498 
456 | 2.00 | bar   | 2010-10-11 | 2122 
123 | 1.00 | baz   | 2010-08-01 | 1497 
456 | 2.00 | quux   | 2010-10-05 | 2121 
456 | 1.95 | quux   | 2010-09-07 | 2120 

我想生產:

id | cur_rate | cur_ver | updated_on | prev_rate | prev_ver | prev_updated 
-----+----------+---------+------------+-----------+----------+------------- 
123 | 1.20  | 1500 | 2010-10-18 | 1.10  | 1498  | 2010-10-08 
456 | 2.10  | 2123 | 2010-10-12 | 2.00  | 2122  | 2010-10-11 

請注意,我想找一份率從最新的條目不同的最新條目。

我試過各種方法,但要麼得到太多的結果,要麼根本沒有。有什麼建議麼?

回答

5

有幾種方法可以實現這一點。這裏有一種方法

Declare @table as table( 
id int, 
rate decimal(10,5) , 
uninteresting varchar(10) , 
updated_on date, 
version int) 
INSERT INTO @table 
VALUES 
(123 , 1.20 , 'foo  ' , '2010-10-18' , 1500), 
(456, 2.1, ' bar   ', ' 2010-10-12 ', 2123), 
(123, 1.2, ' baz   ', ' 2010-10-10 ', 1499), 
(123, 1.1, ' baz   ', ' 2010-10-08 ', 1498), 
(456, 2, ' bar   ', ' 2010-10-11 ', 2122), 
(123, 1, ' baz   ', ' 2010-08-01 ', 1497), 
(456, 2, ' quux   ', ' 2010-10-05 ', 2121), 
(456, 1.95, ' quux   ', ' 2010-09-07 ', 2120) 


;WITH rates 
    AS (SELECT Row_number() OVER (PARTITION BY curr.id, curr.rate ORDER BY curr.updated_on DESC) AS rn, 
      curr.id, 
      curr.rate  cur_rate, 
      curr.version  cur_ver, 
      curr.updated_on, 
      previous.rate  prev_rate, 
      previous.version prev_ver, 
      previous.updated_on prev_updated 
      FROM 
       @table curr 
       LEFT JOIN @table previous 
       ON curr.id = previous.id 
        AND curr.rate <> previous.rate 
        AND curr.updated_on > previous.updated_on 

    ) 
    SELECT 
      id, 
      cur_rate, 
      cur_ver, 
      updated_on, 
      prev_rate, 
      prev_ver, 
      prev_updated 
    FROM 
      rates 
    WHERE 
      rn = 1 

產生這樣的結果

id   cur_rate cur_ver  updated_on prev_rate prev_ver prev_updated 
----------- -------- ----------- ---------- --------- ----------- ------------ 
123   1.00000 1497  2010-08-01 NULL  NULL  NULL 
123   1.10000 1498  2010-10-08 1.00000 1497  2010-08-01 
123   1.20000 1500  2010-10-18 1.10000 1498  2010-10-08 
456   1.95000 2120  2010-09-07 NULL  NULL  NULL 
456   2.00000 2122  2010-10-11 1.95000 2120  2010-09-07 
456   2.10000 2123  2010-10-12 2.00000 2122  2010-10-11 

如果你改變了RN通過例如掉落率在分區 (PARTITION BY curr.id ORDER BY curr.updated_on DESC) AS rn,

id   cur_rate cur_ver  updated_on prev_rate prev_ver prev_updated 
----------- -------- ----------- ---------- --------- ----------- ------------ 
123   1.20000 1500  2010-10-18 1.10000 1498  2010-10-08 
456   2.10000 2123  2010-10-12 2.00000 2122  2010-10-11 
+0

感謝您的快速響應,但我遇到了這個問題。除了'rn',我在'(選擇row_number()over()as ...)'中指定的所有列都得到'無效列名'。當然,我在這個例子中給出的名字並不完全匹配我的數據庫列,但是我已經替換了這些值,並且重複了幾次;我確定我有正確的表格和欄目名稱。我還重構了查詢,例如'rate(select rn = row_number()over(partition ...),id,rate,...)',同樣的問題。 – Val

+0

這不會顯示他以前的速率**不同於當前的** **,僅僅是第二最近的速率 – JNK

+0

+1編輯 – JNK

1

對於基於我將在我的測試沒有工作的方式有些道理的。我不得不這樣添加previous.date在ROW_NUMBER順序:

ROW_NUMBER() OVER (PARTITION BY curr.id, curr.status_id ORDER BY curr.row_created_date DESC, previous.row_created_date DESC) AS rn, 

我的情況略有不同,我需要還可以去來回我的「地位」,因爲它可能會改變。這是爲我工作的代碼。

DECLARE @mytemptable TABLE 
(
    tableid INT IDENTITY(1,1) PRIMARY KEY, 
    id INT, 
    status_id INT, 
    [user_id] INT, 
    row_created_date DATE 
) 

INSERT INTO @mytemptable VALUES (112266980, 1, 5, GETDATE()-21); 
INSERT INTO @mytemptable VALUES (112266980, 2, 5, GETDATE()-14); 
INSERT INTO @mytemptable VALUES (112266980, 3, 6, GETDATE()-7); 
INSERT INTO @mytemptable VALUES (112266980, 4, 8, GETDATE()); 
INSERT INTO @mytemptable VALUES (112277777, 1, 5, GETDATE()-21); 
INSERT INTO @mytemptable VALUES (112277777, 2, 5, GETDATE()-14); 
INSERT INTO @mytemptable VALUES (112277777, 3, 5, GETDATE()-6); 
INSERT INTO @mytemptable VALUES (112266666, 1, 5, GETDATE()-40); 
INSERT INTO @mytemptable VALUES (112266666, 2, 5, GETDATE()-30); 
INSERT INTO @mytemptable VALUES (112266666, 3, 5, GETDATE()-25); 
INSERT INTO @mytemptable VALUES (112266666, 2, 5, GETDATE()-20); 

SELECT * FROM @mytemptable ORDER BY id, row_created_date DESC 

;WITH statuses 
      AS (
       SELECT 
       ROW_NUMBER() OVER (PARTITION BY curr.id, curr.status_id, curr.row_created_date ORDER BY curr.row_created_date DESC, previous.row_created_date DESC) AS rn, 
       curr.id, 
       curr.status_id curr_status_id, 
       curr.user_id AS curr_user_id, 
       curr.row_created_date AS curr_datetime, 
       previous.status_id prev_status_id, 
       previous.user_id AS prev_user_id, 
       previous.row_created_date AS prev_datetime 
       FROM 
       @mytemptable AS curr 
       LEFT JOIN @mytemptable AS previous 
        ON curr.id = previous.id 
         AND curr.status_id <> previous.status_id 
         AND curr.row_created_date > previous.row_created_date 
      ) 
    SELECT 
     id, 
     curr_status_id, 
     curr_user_id, 
     curr_datetime, 
     prev_status_id, 
     prev_user_id, 
     prev_datetime 
    FROM 
     statuses 
    WHERE 
     rn = 1 
    ORDER BY 
     id, curr_datetime DESC 
相關問題