Дедуплицируйте таблицу на основе метки времени с шаблонами повторного выделения - PullRequest
1 голос
/ 02 апреля 2011

Хорошо.Прежде всего позвольте мне извиниться, если этот вопрос был рассмотрен.Я посмотрел , но ни одно из решений не касалось деталей моей проблемы.

У меня есть таблица, содержащая более 160 миллионов строк данных о состоянии сотрудников / серверов, отслеживающих время.Я хочу создать подмножество этих данных и удалить повторения, которые происходят повсюду, НО сохраняет последовательность изменений по мере их возникновения.Сокращение для большинства сотрудников будет с 700 строк (и растет) до 1.

Вот упрощенный пример того, к чему я пытаюсь добраться:

Given:

RowID  Employee  Server  Timestamp
-----  --------  ------  ---------
5      E000001   Serv-B  May01
4      E000001   Serv-A  Apr01
3      E000001   Serv-B  Mar01
2      E000001   Serv-A  Feb01
1      E000001   Serv-A  Jan01

Doing a "Min(Timestamp) Group By Employee, Server" would yield:
Employee Server  Timestamp
-------- ------  ---------
E000001  Serv-B  Mar01
E000001  Serv-A  Jan01
.
What I need is:
Employee Server  Timestamp
-------- ------  ---------
E000001  Serv-B  May01
E000001  Serv-A  Apr01
E000001  Serv-B  Mar01
E000001  Serv-A  Jan01

Таблица ипроцесс, который передает его, не принадлежит нашей группе, поэтому я не могу повлиять на решение там, и я бы предпочел не застрять с копией всей вещи.Я не могу реально сделать подход курсора / RBAR, учитывая размер таблицы.Если меня загнали в угол, я могу написать прикладную программу для этого, но мне было интересно, есть ли у какого-нибудь из богов из SQoLympus мудрость сделать это в хранимой процедуре.Заранее спасибо!

Редактировать: Это SQL Server 2008 - Извините, что не упомянул это.

Ответы [ 2 ]

1 голос
/ 02 апреля 2011

Если SQL Server (при условии, что я правильно понял ваши требования)

/*Set up test table*/
DECLARE @T TABLE (
  RowID       INT,
  Employee    CHAR(7),
  [Server]    CHAR(6),
  [timestamp] DATETIME );

INSERT INTO @T
SELECT 5,'E000001','Serv-B',  '20010501' UNION ALL
SELECT 4,'E000001','Serv-A',  '20010401' UNION ALL
SELECT 3,'E000001','Serv-B',  '20010301' UNION ALL
SELECT 2,'E000001','Serv-A',  '20010201' UNION ALL
SELECT 1,'E000001','Serv-A',  '20010101';

WITH cte
     As (SELECT ROW_NUMBER() OVER (PARTITION BY Employee ORDER BY RowID) -
                ROW_NUMBER() OVER (PARTITION BY Employee, Server
                                       ORDER BY RowID) AS Grp,
                *
         FROM   @T),
     cte2
     AS (SELECT *,
                ROW_NUMBER() OVER (PARTITION BY Employee, Grp ORDER BY RowID) AS
                Rn
         FROM   cte)

/* Edit: Actually - You want a SELECT not a DELETE I think?
DELETE FROM cte2 WHERE  Rn > 1*/

SELECT   RowID, Employee, [Server], [timestamp]
FROM cte2
WHERE  Rn = 1
0 голосов
/ 02 апреля 2011

Вы не сказали, какую БД вы используете, но если, например, это Oracle, вы можете использовать аналитические функции lag или lead для ссылки на предыдущую или следующую строку.

select employee, server, timestamp 
from
   (select employee, server, timestamp,
    lag(employee) over (order by employee, server, timestamp) prev_employee 
    lag(server) over (order by employee, server, timestamp) prev_server 
    from table
   )
where not (employee = prev_employee and server = prev_server)
...