2011-10-18 17 views
1

メインテーブルの変更を記録する履歴テーブルを持つSQL Server 2008データベースがあります。私は、 'レート'列の現在(最新)の値と、最新とは異なる最新の前の値を報告する必要があります。私が生産したい履歴テーブルの列の現在と前の値を比較する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

これを達成するには、いくつかの方法があります。ここでは、例えば、パーティション内の割合をドロップするRNを変更した場合は

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 

を生産する一つの方法です (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'以外の '(select row_number()over()as ...)'で指定されたすべての列に対して' invalid column name 'を取得します。もちろん、私がこの例で与えた名前は、私のDBの列と正確には一致しませんが、値を置き換えて何度も渡しました。私は正しい表と列の名前を持っていると確信しています。私はまた '(rn = row_number()を超えて(パーティション...)、id、rate、...)'と同じ問題を再構築しました。 – Val

+0

これは彼に前回のレート**現在のものとは異なる**を表示しませんでした**ちょうど2番目に新しいレート – JNK

+0

+1の編集 – JNK

1

を取得します。私はこのようなことでROW_NUMBER順にprevious.dateを追加する必要がありました:

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 
関連する問題