Как группировать записи по DateRange - PullRequest
1 голос
/ 09 февраля 2012

Как сгруппировать записи по диапазону дат в sql?

Рассмотрим эту структуру таблицы.

 Key       ID       VISITDATE
 1         1        2011-01-07
 2         1        2011-01-09
 3         2        2011-01-10
 4         1        2011-01-12
 5         3        2011-01-12
 6         1        2011-01-18
 7         2        2011-01-21
 9         1        2011-02-28
 10        2        2011-03-21
 11        1        2011-01-06
 12        1        2011-02-29

Мне нужно получить количество вхождений.если у вас есть два посещения в течение 10 дней для одного и того же идентификатора, то следует учитывать только одно посещение.поэтому для приведенного примера число вхождений для идентификатора 1 = 3 (01 / 06,01 / 18,02 / 28)

Рекурсивный запрос CTE высоко ценится.

Ответы [ 3 ]

1 голос
/ 09 февраля 2012

Вы не уточняете, как будут определены диапазоны дат

Если вы начинаете диапазоны с сегодняшнего дня, вы можете сделать это так:

SELECT     id, COUNT(DISTINCT DATEDIFF(dd, visitdate, GETDATE()) / 10) AS Expr1
FROM         test
GROUP BY id

Если вы хотите начать диапазоны с самой последней даты на данных, вы можете сделать это следующим образом

DECLARE @maxdate as datetime
SET @maxdate = (select MAX(visitdate) from test)

SELECT     id, COUNT(DISTINCT DATEDIFF(dd, visitdate, @maxdate) / 10) 
FROM         test
GROUP BY id

Запрос, подобный этому, сработает для случая @Dems указал

SELECT id, count(DISTINCT visitdate)
FROM (
    SELECT   id, visitdate,
        (SELECT MAX(visitdate) 
        FROM test AS t 
        WHERE t.id = test.id AND t.visitdate<test.visitdate) AS prev_date
    FROM     test ) as temp
WHERE DATEDIFF(dd, prev_date, visitdate) > 10 OR prev_date IS NULL
GROUP BY id

Приведенный выше запрос не учитывает записи с таким же идентификатором, для которых существует другая запись с датой, меньшей на десять дней

Если вы хотите разделить календарь, начиная с минимальной даты для каждого идентификатора, вы можете сделать следующее

SELECT     t.id, COUNT(DISTINCT DATEDIFF(dd, mindate, visitdate) / 10) 
FROM         test as t JOIN 
  (SELECT id, MIN(visitdate) AS mindate FROM test GROUP BY id) as mindates
    ON t.id = mindates.id
GROUP BY t.id
1 голос
/ 09 февраля 2012

Я знаю, что вы просили рекурсивный CTE, но без новых улучшений управления окнами в SQL Server 2012 (FIRST_VALUE () и т. Д.) Я думаю, что писать так будет непросто, когда вы должны отслеживать не только предыдущая строка, но также и более ранние строки одновременно. Вот версия курсора, которая, я считаю, достигает того, что вы хотите:

DECLARE @f TABLE([Key] INT, ID INT, VISITDATE DATE);

INSERT @f VALUES
  (1 ,1,'2011-01-07'), (2 ,1,'2011-01-09'), (3 ,2,'2011-01-10'), (4 ,1,'2011-01-12'),
  (5 ,3,'2011-01-12'), (6 ,1,'2011-01-18'), (7 ,2,'2011-01-21'), (9 ,1,'2011-02-28'), 
  (10,2,'2011-03-21'), (11,1,'2011-01-06'), (12,1,'2011-03-01');

DECLARE @ID INT, @dt DATE;

DECLARE @result TABLE(ID INT, FirstDate DATE, VisitCount INT);

DECLARE c CURSOR LOCAL STATIC READ_ONLY FORWARD_ONLY
    FOR SELECT ID, VISITDATE FROM @f ORDER BY ID, VISITDATE;

OPEN c;

FETCH NEXT FROM c INTO @ID, @dt;

WHILE @@FETCH_STATUS = 0
BEGIN
    IF NOT EXISTS 
    (
        SELECT 1 FROM @result WHERE ID = @ID
            AND DATEDIFF(DAY, FirstDate, @dt) <= 10 -- maybe < 10?
    )
    INSERT @result SELECT @ID, @dt, 1;

    FETCH NEXT FROM c INTO @ID, @dt;
END

SELECT ID, FirstDate FROM @result;

SELECT ID, VisitCount = COUNT(*) FROM @result GROUP BY ID;

CLOSE c;
DEALLOCATE c;

Результаты:

ID          FirstDate
----------- ----------
1           2011-01-06
1           2011-01-18
1           2011-02-28
2           2011-01-10
2           2011-01-21
2           2011-03-21
3           2011-01-12


ID          VisitCount
----------- -----------
1           3
2           3
3           1

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

0 голосов
/ 09 февраля 2012

Создайте скалярную функцию, которая возвращает одну и ту же дату для всех дат в заданном диапазоне, а затем группируйте по ней.

...