2010-01-05 2 views
2

База данных, в которой я сейчас работаю, - это научный инструмент, который записывает данные в определенные моменты времени. Мой инструмент записывается в секунду, но с разрешением 5 секунд.Удаление дубликатов в SQL Server - Необычный сценарий

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-ю позицию, поскольку это может не сработать, если мой instument испортился и дал мне 4 строки в db. Я бы хотел, чтобы какой-то способ сравнения строк вокруг каждого образца и конденсация на основе этого.

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

+0

Жесткий. Могут ли две «реальные» точки данных в одной строке совпадать? Другими словами, вы могли бы получить 10 последовательных чтений 602, а не только 5? – Aaronaught

+0

Кроме того, вы выражаете обеспокоенность тем, что инструмент может давать только 4 строки - будет ли время еще правильным, т. Е. Общий временной интервал, использованный этим образцом, составляет 5 секунд, даже если вы не получили все 5 строк? – Aaronaught

+0

Какой инструмент вы используете, чтобы записывать частицы в MSSQL? Ваш прибор не слышал о NetCDF или других стандартных форматах научных данных? – BobMcGee

ответ

1

ОК, поэтому у меня было время, чтобы преобразовать решение 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 

Спасибо всем, что помогли.

0

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

1

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

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 и т. д. нет перекрытия.

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

+0

Это было довольно хорошо по моим данным, но не на 100%. Как вы говорите, если данные были предсказуемыми, это было бы здорово; но, к сожалению, мои данные не так прощают. Благодарю. – Geodesic

1

Я оставил комментарий - я собираюсь предположить, что физическая точка данных по-прежнему занимает 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 

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

+0

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

2

Используйте обычное разделение 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; 

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

+0

Этот ответ был самым близким к тому, что мне нужно, но он сохранял проблемы, когда мои данные были не такими, как должны. Спасибо за помощь! – Geodesic

+0

Я забыл разделить на 5, чтобы сгруппировать все записи за один и тот же 5-секундный интервал. Обновлено. –

0

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

Смежные вопросы