SQL-запрос для сравнения текущего и предыдущего значения в столбце таблицы истории - PullRequest
2 голосов
/ 18 октября 2011

У меня есть база данных SQL Server 2008 с таблицей истории для записи изменений в основной таблице.Мне нужно сообщить текущее (последнее) значение столбца 'rate' и самое последнее предыдущее значение, отличное от текущего.

Итак, что-то вроде:

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

Iхочу произвести:

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

Обратите внимание, что я ищу последнюю запись, где скорость отличается от самой последней записи.

Я пробовал разные подходы, но либо получаюслишком много результатов или их нет вообще.Есть предложения?

Ответы [ 2 ]

6 голосов
/ 18 октября 2011

Есть несколько способов сделать это. Вот один из способов

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
1 голос
/ 24 февраля 2015

По какой-то причине, из-за того, как я вставлял тест, это не сработало. Мне пришлось добавить предыдущий.даты в порядке 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
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...