Удаление дубликатов в SQL Server - необычный сценарий - PullRequest
2 голосов
/ 05 января 2010

База данных, над которой я сейчас работаю, предназначена для научного инструмента, который записывает данные в определенные моменты времени. Мой инструмент записывает в секунду, но с разрешением 5 секунд.

ID      Total Particles  DateandTime
38313   602              2009-01-27 16:25:48.000
38314   602              2009-01-27 16:25:49.000
38315   602              2009-01-27 16:25:50.000
38316   602              2009-01-27 16:25:51.000
38317   602              2009-01-27 16:25:52.000
38318   553              2009-01-27 16:25:53.000
38319   553              2009-01-27 16:25:54.000
38320   553              2009-01-27 16:25:55.000
38321   553              2009-01-27 16:25:56.000
38322   553              2009-01-27 16:25:57.000
38323   515              2009-01-27 16:25:58.000
38324   515              2009-01-27 16:25:59.000
38325   515              2009-01-27 16:26:00.000
38326   515              2009-01-27 16:26:01.000
38327   515              2009-01-27 16:26:02.000

Это полезно для нас в некоторых ситуациях, но не относится к этой части проекта. Я хотел бы свернуть эти данные так, чтобы был один результат за 5 секунд (скажем, последняя секунда может содержать все данные для соглашения).

Я бы предпочел решение, которое не пропускало 4 строки и отображало 5-ю, потому что это может не сработать, если мой инструмент испортился и дал мне только 4 строки в БД. То, что я хотел бы, это какой-то способ сравнения строк вокруг каждого образца и сжатия на основе этого.

Я не знаю, с чего начать такую ​​операцию, поэтому любая помощь будет признательна.

Ответы [ 6 ]

2 голосов
/ 05 января 2010

Используйте обычное разбиение ROW_NUMBER () для дубликатов и используйте соответствующую схему разбиения.

with cte as (
 select ID, Total, Particles, DateandTime,
   row_number() over (
    partition by datediff(seconds,'19000101',DateandTime)/5
    order by DateandTime) as rn
 from table)
select * from cte
where rn = 1; 

Не могу прокомментировать, насколько это эффективно без знания точной схемы (включая индексы) таблиц.

1 голос
/ 07 января 2010

ОК, поэтому у меня было некоторое время, чтобы преобразовать свое решение MatLab в SQL. Не слишком уверен, действительно ли это так здорово, но работает довольно хорошо. Мое решение MatLab заняло более 30 минут, чтобы вычислить результат для 2,2 миллиона строк, которые у меня были, а версия SQL заняла 4 минуты!

Вот код для справки, если у кого-то возникнет подобная проблема в будущем:

DECLARE @i INT
DECLARE @Count INT
DECLARE @Selection INT
DECLARE @Result TABLE (ID INT)

SET @i = 1
SET @Count = (SELECT count(*) FROM CFLAPS_AllStations)

WHILE (@i <= @Count)
BEGIN
   IF @i < @Count - 4
    BEGIN
        SET @Selection = (SELECT TotalParticlesCount FROM CFLAPS_AllStations WHERE ID = @i)
        IF  @Selection = (SELECT TotalParticlesCount FROM CFLAPS_AllStations WHERE ID = @i+4)
        BEGIN   
            INSERT INTO @Result SELECT ID FROM CFLAPS_AllStations WHERE ID = @i
        END
        ELSE
        BEGIN
            INSERT INTO @Result SELECT ID FROM CFLAPS_AllStations WHERE ID = @i

            SET @i =  
            CASE 
                WHEN @Selection = (SELECT TotalParticlesCount FROM CFLAPS_AllStations WHERE ID = @i+3) THEN @i-1
                WHEN @Selection = (SELECT TotalParticlesCount FROM CFLAPS_AllStations WHERE ID = @i+2) THEN @i-2
                WHEN @Selection = (SELECT TotalParticlesCount FROM CFLAPS_AllStations WHERE ID = @i+1) THEN @i-3
                WHEN @Selection = (SELECT TotalParticlesCount FROM CFLAPS_AllStations WHERE ID = @i) THEN @i-4
            END
        END
   END
   ELSE
   BEGIN
      INSERT INTO @Result SELECT ID FROM CFLAPS_AllStations WHERE ID = @i
   END
   SET @i = @i+5
END

SELECT p.ID, p.TotalParticlesCount, p.FullDateTime FROM CFLAPS_AllStations as p, @Result as q WHERE p.ID = q.ID

Точно так же вы все знаете, почему это было важно: прибор всегда регистрирует 5 секунд идентичных данных, но если он останавливает запись, скажем, во второй 3 цикла; он не будет записывать 4-ю и 5-ю секунды, и поэтому в данных появляются пробелы. Мне удалось проверить это с помощью цикла while, и мне удалось зафиксировать все эти несоответствия.

Окончательный вывод:

ID  TotalParticles  DateTime
1       745     2009-06-23 00:00:00.000
6       727     2009-06-23 00:00:05.000
11      771     2009-06-23 00:00:10.000
16      837     2009-06-23 00:00:15.000
21      768     2009-06-23 00:00:20.000
26      703     2009-06-23 00:00:25.000
31      822     2009-06-23 00:00:30.000
36      730     2009-06-23 00:00:35.000
41      731     2009-06-23 00:00:40.000
46      706     2009-06-23 00:00:45.000
51      733     2009-06-23 00:00:50.000
...
2290089 677     2009-06-22 23:59:15.000
2290094 720     2009-06-22 23:59:20.000
2290099 771     2009-06-22 23:59:25.000
2290104 770     2009-06-22 23:59:30.000
2290109 761     2009-06-22 23:59:35.000
2290114 851     2009-06-22 23:59:40.000
2290119 801     2009-06-22 23:59:45.000
2290124 754     2009-06-22 23:59:50.000
2290129 702     2009-06-22 23:59:55.000

Спасибо всем, кто выручил.

1 голос
/ 05 января 2010

Я оставил комментарий - я собираюсь предположить, что физическая точка данных по-прежнему занимает 5 секунд, даже если вы не получите 5 строк.Если это так, то может работать следующее:

Сначала создайте функцию секунд:

CREATE FUNCTION dbo.GetTotalSeconds(@dt datetime)
RETURNS bigint
AS
BEGIN
    RETURN DATEDIFF(ss, '1753-01-01', @dt)
END

Теперь этот запрос:

DECLARE
    @StartID int,
    @EndID int

SET @StartID = 38313
SET @EndID = 40313

DECLARE @StartSeconds bigint

SELECT TOP 1 @StartSeconds = dbo.GetSeconds(DateandTime)
FROM DataPoints
WHERE ID >= @StartID
ORDER BY ID ASC

SELECT p.ID, p.Total, p.Particles, p.DateandTime
FROM
(
    SELECT DISTINCT
        (dbo.GetSeconds(DateandTime) - @StartSeconds) / 5 AS SecondsInterval
    FROM DataPoints
    WHERE ID >= @StartID
    AND ID <= @EndID
) g
INNER JOIN DataPoints p
ON (dbo.GetSeconds(p.DateandTime) - @StartSeconds) = g.SecondsInterval
ORDER BY g.SecondsInterval

Производительность будет довольно слабой, но онадолжен обрабатывать все крайние случаи.

1 голос
/ 05 января 2010

если поток достаточно предсказуемый, вы можете сделать что-то вроде:

select id, particles, time from log where
id in (select min(id) from log group by
datediff(second, (select min(time) from log), time) / 5)

получит первое чтение через каждые 5 секунд. первый интервал охватывает секунды 1 - 5 в журнале. следующий интервал - секунды 6 - 10 и т. д. перекрытия нет.

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

0 голосов
/ 06 января 2010

Спасибо за вашу помощь, ребята. Я думаю, что если бы у меня было немного больше времени на эту проблему, я бы смог использовать все ваши примеры и заставить что-то работать напрямую в SQL - но у меня нет такой свободы. Проект, над которым я работаю, в основном написан на MatLab, поэтому я вытащил данные ID и TotalParticles из БД, а затем в Matlab я провел проверку столбца TotalParticles. Выходные данные этого сценария - это значения идентификаторов, которые мне требуются для свернутой базы данных, которые я передам в простой оператор выбора и который, в свою очередь, создаст требуемое представление.

0 голосов
/ 05 января 2010

Вероятно, лучший способ (если вы хотите сохранить все «необработанные» данные) - это иметь какой-то триггер, который вставляется в сводную таблицу при вставке «необработанной» таблицы. Этот триггер определит основу для передачи информации в зависимости от времени. Это будет означать, что вы получите много данных, но я ожидаю, что это целесообразно сохранить. Стоит отметить, что выполнение этого через триггер может быть плохим (медленным), потому что это будет происходить для каждой вставки. Возможно, более уместно отлавливать эту информацию на уровне приложения, но я не знаю, возможно ли это ...

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...