Гистограмма на основе нестандартных дат в SQL Server - PullRequest
3 голосов
/ 06 мая 2009

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

1 May 2005 - 30 Apr 2006 | 525
1 May 2006 - 30 Apr 2007 | 673
1 May 2007 - 30 Apr 2008 | 892
1 May 2006 - 30 Apr 2009 | 1047

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

SELECT YEAR([date]) AS [year], COUNT(*) AS cnt 
FROM logins
GROUP BY YEAR([date])
ORDER BY [year]

Но это не дает мне диапазоны данных, которые я хочу. Как это можно сделать?

Ответы [ 2 ]

3 голосов
/ 06 мая 2009
declare @baseDate datetime
set @baseDate = '1 May 2005'

SELECT
    datediff(year, @baseDate, [date]) AS YearBucket 
    ,COUNT(*) AS cnt 
FROM logins
GROUP BY datediff(year, @baseDate, [date])
ORDER BY datediff(year, @baseDate, [date])

РЕДАКТИРОВАТЬ - извинения, вы правы. Вот исправленная версия (я должен был использовать тестовую таблицу, чтобы начать с ...)

create table logins (date datetime, foo int)
insert logins values ('1 may 2005', 1)
insert logins values ('1 apr 2006', 2)
insert logins values ('1 may 2006', 3)

declare @baseDate datetime
set @baseDate = '1 May 2005'

SELECT
    datediff(day, @baseDate, [date]) / 365 AS YearBucket 
    ,COUNT(*) AS cnt 
FROM logins
GROUP BY datediff(day, @baseDate, [date]) / 365
ORDER BY datediff(day, @baseDate, [date]) / 365

Измените единицы измерения даты, если вы хотите больше детализации, чем дни.

РЕДАКТИРОВАТЬ # 2 - хорошо, вот более надежное решение, которое обрабатывает високосные годы :) РЕДАКТИРОВАТЬ № 3 - На самом деле это не обрабатывает високосные годы, вместо этого он позволяет указывать переменные интервалы времени Используйте безопасный метод високосного года с dateadd (year, 1, @baseDate).

declare @baseDate datetime, @interval datetime
--@interval is expressed as time above 0 time (1/1/1900)
select @baseDate = '1 May 2005', @interval = '1901'

declare @timeRanges table (beginIntervalInclusive datetime, endIntervalExclusive datetime)
declare @i int
set @i = 1
while @i <= 10
begin
    insert @timeRanges values(@baseDate, @baseDate + @interval)
    set @baseDate = @baseDate + @interval
    set @i = @i + 1
end

SELECT
    tr.beginIntervalInclusive,
    tr.endIntervalExclusive,
    COUNT(*) AS cnt 
FROM logins join @timeRanges as tr
    on logins.date >= tr.beginIntervalInclusive
        and logins.date < tr.endIntervalExclusive
GROUP BY  tr.beginIntervalInclusive, tr.endIntervalExclusive
ORDER BY  tr.beginIntervalInclusive
1 голос
/ 06 мая 2009

Если вы можете найти способ определения диапазонов дат в отдельной таблице, выберите метку и два столбца дат и объедините их в своем основном запросе в зависимости от ваших таблиц.

Select Count(*) as NoLogons, DateRangeLabel
From logins a
inner join
(
Select
DateRangeLabel, StartDate, EndDate
From tblMyDates 
) b
on a.date between b.startdate and b.enddate
Group by DateRangeLabel
...