2013-11-13 7 views
0

У меня есть таблица, в которой хранится информация о обнаружении bluetooh. Например:Группировка записей по времени в clumps - SQL SERVER 2008

MACaddress   | DetectorID | PollingIntervalStart  | PollingIntervalEnd 
00:00:00:00:00:01 | 3  | 2012-03-26 16:51:09.000 | 2012-03-26 16:51:19.000 
00:00:00:00:00:01 | 3  | 2012-03-26 16:51:24.000 | 2012-03-26 16:51:28.000 
00:00:00:00:00:01 | 3  | 2012-03-26 16:51:35.000 | 2012-03-26 16:51:49.000 
00:00:00:00:00:01 | 3  | 2012-03-26 16:51:55.000 | 2012-03-26 16:52:09.000 
00:00:00:00:32:11 | 3  | 2012-03-26 17:00:43.000 | 2012-03-26 17:01:19.000 
00:00:00:00:20:F1 | 1  | 2012-03-26 17:02:52.000 | 2012-03-26 16:53:02.000 
... 

00:00:00:00:00:01 | 3  | 2012-03-26 19:21:19.000 | 2012-03-26 19:21:48.000 
00:00:00:00:00:01 | 3  | 2012-03-26 19:21:59.000 | 2012-03-26 19:22:51.000 
00:00:00:00:00:01 | 3  | 2012-03-26 19:22:19.000 | 2012-03-26 19:22:31.000 
00:00:00:00:20:F1 | 1  | 2012-03-26 20:23:49.000 | 2012-03-26 19:50:30.000 

Детектор ID является идентификатором детектора bluetooth, который опросил устройство. Как вы можете видеть, иногда устройство может задерживаться в радиусе опроса детектора, поэтому мы получаем кластер обнаружения того же устройства. То, что я хочу сделать, это группировать кластеры и принимать первое обнаружение (что означает min(DetectionTime)) этого кластера (скажем, мы определяем кластер для обозначения того же устройства, опрошенного несколько раз за три минуты). Обратите внимание, что длина интервала опроса для детекторов не является постоянной. Например, для кластера

00:00:00:00:00:01 | 3  | 2012-03-26 16:51:09.000 | 2012-03-26 16:51:19.000 -- take this record 
00:00:00:00:00:01 | 3  | 2012-03-26 16:51:24.000 | 2012-03-26 16:51:28.000 
00:00:00:00:00:01 | 3  | 2012-03-26 16:51:35.000 | 2012-03-26 16:51:49.000 
00:00:00:00:00:01 | 3  | 2012-03-26 16:51:55.000 | 2012-03-26 16:52:09.000 

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

MACaddress   | DetectorID | PollingIntervalStart  | PollingIntervalEnd 
00:00:00:00:00:01 | 3  | 2012-03-26 16:51:09.000 | 2012-03-26 16:51:19.000 
00:00:00:00:32:11 | 3  | 2012-03-26 17:00:43.000 | 2012-03-26 17:01:19.000 
00:00:00:00:20:F1 | 1  | 2012-03-26 17:02:52.000 | 2012-03-26 16:53:02.000 
... 

00:00:00:00:00:01 | 3  | 2012-03-26 19:21:19.000 | 2012-03-26 19:21:48.000 
00:00:00:00:20:F1 | 1  | 2012-03-26 20:23:49.000 | 2012-03-26 19:50:30.000 

Я попытался с помощью group by, ROW_NUMBER, RANK, DENSE_RANK, и я не могу показаться, чтобы быть в состоянии понять это. Я попытался использовать таблицу подсчета, чтобы сделать временные интервалы и присоединиться к временному интервалу, но это не сработало. Любая помощь приветствуется. Благодарю.

Редактировать

Что я имею в виду «сгустки» является то, что если то же устройство, если обнаружено несколько раз в течение короткого периода времени, то это считается комок. Я определил этот интервал как 3 минуты. Эта длина интервала произвольна, это могло быть любое количество минут, но я просто выбираю 3 минуты. Так что если адрес mac обнаружен в 3:00:22 и 3:00:34 и 3:01:44, все три обнаружения считаются одним комком. Если он был обнаружен в 3:00:22 и 3:07:32, это не коммент.

Это должно быть первое обнаружение скопления. Если у вас есть код для последнего обнаружения скопления, вы можете его также опубликовать. Возможно, я могу попытаться использовать ROW_NUMBER и убывающий порядок, чтобы получить желаемый результат.

Edit 2

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

+0

Вы хотите получить три минуты от MIN (PollingIntervalStart)? Начинается ли через 3 минуты после этого или заканчивается через 3 минуты после этого? Текст все еще просто говорит в течение трех минут минут (DetectionTime), но нуждается в некоторой ясности. Также у вас есть две строки, где конец

+0

Кроме того, важно ли, чтобы вы получили первую строку в скоплении? У меня довольно простой запрос, который получает строку * last * в компе, но я исчерпал количество времени, которое я могу потратить, пытаясь заставить его сделать обратное. –

+0

Я не думаю, что было какое-то замешательство в том, что вы имели в виду под «clumps» - именно там, где вы это измеряете. Например. если один опрос начался в полдень и закончился в 12:01, то другой опрос начался в 12:02:59 и закончился в 12:03:01, это произошло «в течение трех минут»? Другими словами, мы игнорируем время окончания? –

ответ

0

Я нашел ответ, слегка изменив Aaron Bertrand's answer.

Настройка таблицы:

DECLARE @d TABLE 
(
    MACaddress VARCHAR(32), 
    DetectorID INT, 
    PollingIntervalStart DATETIME2(0), 
    PollingIntervalEnd DATETIME2(0) 
); 

INSERT @d VALUES 
('00:00:00:00:00:01',3,'2012-03-26 16:51:09.000','2012-03-26 16:51:19.000'), 
('00:00:00:00:00:01',3,'2012-03-26 16:51:24.000','2012-03-26 16:51:28.000'), 
('00:00:00:00:00:01',3,'2012-03-26 16:51:35.000','2012-03-26 16:51:49.000'), 
('00:00:00:00:00:01',3,'2012-03-26 16:51:55.000','2012-03-26 16:52:09.000'), 
('00:00:00:00:32:11',3,'2012-03-26 17:00:43.000','2012-03-26 17:01:19.000'), 
('00:00:00:00:20:F1',1,'2012-03-26 17:02:52.000','2012-03-26 16:53:02.000'), 
('00:00:00:00:00:01',3,'2012-03-26 19:21:19.000','2012-03-26 19:21:48.000'), 
('00:00:00:00:00:01',3,'2012-03-26 19:21:59.000','2012-03-26 19:22:51.000'), 
('00:00:00:00:00:01',3,'2012-03-26 19:22:19.000','2012-03-26 19:22:31.000'), 
('00:00:00:00:20:F1',1,'2012-03-26 19:49:49.000','2012-03-26 19:50:30.000'); 

Я делаю два модификации кода Аарона. Я сделал заказ подзапроса в порядке убывания. И в состоянии WHERE NOT EXISTS я заменил DATEADD с DATEDIFF(MINUTE, x2.PollingIntervalStart, x.PollingIntervalStart) < 3.

;WITH x AS 
(
    SELECT 
    *, 
    ROW_NUMBER() OVER 
     (PARTITION BY MacAddress, DetectorID ORDER BY PollingIntervalStart DESC) AS RN 
    FROM @d 
) 
select * from x 
WHERE NOT EXISTS 
(
    SELECT 1 FROM x AS x2 
    WHERE x2.MACaddress = x.MacAddress 
    AND x2.DetectorID = x2.DetectorID 
    AND x2.rn = x.rn + 1 
    -- x2.PollingIntervalStart is always less than x.PollingIntervalStart becasue of x2.rn = x.rn + 1 condition 
    -- this works because the cte query is ordered in descending order 
    AND DATEDIFF(MINUTE, x2.PollingIntervalStart, x.PollingIntervalStart) < 3 
) 
ORDER BY x.PollingIntervalStart; 

Спасибо Аарон.

2

Учитывая эти выборочные данные (я исправил свои строки, в которых время начала> время окончания, не кажется правильным):

DECLARE @d TABLE 
(
    MACaddress VARCHAR(32), 
    DetectorID INT, 
    PollingIntervalStart DATETIME2(0), 
    PollingIntervalEnd DATETIME2(0) 
); 

INSERT @d VALUES 
('00:00:00:00:00:01',3,'2012-03-26 16:51:09.000','2012-03-26 16:51:19.000'), 
('00:00:00:00:00:01',3,'2012-03-26 16:51:24.000','2012-03-26 16:51:28.000'), 
('00:00:00:00:00:01',3,'2012-03-26 16:51:35.000','2012-03-26 16:51:49.000'), 
('00:00:00:00:00:01',3,'2012-03-26 16:51:55.000','2012-03-26 16:52:09.000'), 
('00:00:00:00:32:11',3,'2012-03-26 17:00:43.000','2012-03-26 17:01:19.000'), 
('00:00:00:00:20:F1',1,'2012-03-26 17:02:52.000','2012-03-26 16:53:02.000'), 
('00:00:00:00:00:01',3,'2012-03-26 19:21:19.000','2012-03-26 19:21:48.000'), 
('00:00:00:00:00:01',3,'2012-03-26 19:21:59.000','2012-03-26 19:22:51.000'), 
('00:00:00:00:00:01',3,'2012-03-26 19:22:19.000','2012-03-26 19:22:31.000'), 
('00:00:00:00:20:F1',1,'2012-03-26 19:49:49.000','2012-03-26 19:50:30.000'); 

Эта идея получает последнюю строку глыбы. Как я уже сказал, я думаю, что это, безусловно, возможно, но я должен двигаться дальше. Это, безусловно, будет проще в SQL Server 2012, что добавит множество функций ранжирования.

;WITH x AS 
(
    SELECT *, rn = ROW_NUMBER() OVER 
    (PARTITION BY MacAddress, DetectorID ORDER BY PollingIntervalStart) 
    FROM @d 
) 
SELECT * FROM x 
WHERE NOT EXISTS 
(
    SELECT 1 FROM x AS x2 
    WHERE x2.MACaddress = x.MacAddress 
    AND x2.DetectorID = x2.DetectorID 
    AND x2.rn = x.rn + 1 
    AND x2.PollingIntervalStart <= DATEADD(MINUTE, 3, x.PollingIntervalStart) 
) 
ORDER BY x.PollingIntervalStart; 

Результаты:

MACaddress   DetectorID PollingIntervalStart PollingIntervalEnd rn 
----------------- ---------- -------------------- ------------------- -- 
00:00:00:00:00:01 3   2012-03-26 16:51:55 2012-03-26 16:52:09 4 
00:00:00:00:32:11 3   2012-03-26 17:00:43 2012-03-26 17:01:19 1 
00:00:00:00:20:F1 1   2012-03-26 17:02:52 2012-03-26 16:53:02 1 
00:00:00:00:00:01 3   2012-03-26 19:22:19 2012-03-26 19:22:31 7 
00:00:00:00:20:F1 1   2012-03-26 19:49:49 2012-03-26 19:50:30 2 

Другая идея получает результаты, которые вы хотите, но использует курсор. Лично я думаю, что есть такие случаи, когда курсор абсолютно приемлем (also see this discussion on running totals pre-2012, и имейте в виду the caveat that you should use proper cursor options), но другие отказываются даже смотреть на них. Является ли это практичным, зависит от размера ваших данных; вы должны проверить.

DECLARE @newTable TABLE 
(
    MACaddress VARCHAR(32), 
    DetectorID INT, 
    PollingIntervalStart DATETIME2(0), 
    PollingIntervalEnd DATETIME2(0) 
); 

DECLARE @PreviousTime DATETIME2(0) = NULL, @ma VARCHAR(32), @de INT, 
    @st DATETIME2(0), @et DATETIME2(0), @rn INT; 

DECLARE c CURSOR LOCAL FAST_FORWARD FOR 
    SELECT *, rn = ROW_NUMBER() OVER 
    (PARTITION BY MacAddress, DetectorID ORDER BY PollingIntervalStart) 
    FROM @d ORDER BY MacAddress, rn; 

OPEN c; 

FETCH c INTO @ma, @de, @st, @et, @rn; 

WHILE @@FETCH_STATUS = 0 
BEGIN 
    IF @rn = 1 OR (@rn > 1 AND DATEDIFF(MINUTE, @PreviousTime, @st) > 3) 
    BEGIN 
    INSERT @newTable SELECT @ma, @de, @st, @et; 
    END 

    SELECT @PreviousTime = @st; 

    FETCH c INTO @ma, @de, @st, @et, @rn; 
END 

SELECT * FROM @newTable ORDER BY PollingIntervalStart; 

CLOSE c; DEALLOCATE c; 

Результаты:

MACaddress   DetectorID PollingIntervalStart PollingIntervalEnd 
----------------- ---------- -------------------- ------------------- 
00:00:00:00:00:01 3   2012-03-26 16:51:09 2012-03-26 16:51:19 
00:00:00:00:32:11 3   2012-03-26 17:00:43 2012-03-26 17:01:19 
00:00:00:00:20:F1 1   2012-03-26 17:02:52 2012-03-26 16:53:02 
00:00:00:00:00:01 3   2012-03-26 19:21:19 2012-03-26 19:21:48 
00:00:00:00:20:F1 1   2012-03-26 19:49:49 2012-03-26 19:50:30 
Смежные вопросы