Pregunta

Tengo datos de inicio de sesión de usuario con marcas de tiempo y lo que me gustaría hacer es obtener un histograma de inicios de sesión por año, pero el año comienza en una fecha arbitraria. Por ejemplo, quiero el siguiente tipo de información:

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

Las etiquetas en la primera columna no son importantes, pero los intervalos de fechas sí lo son. Sé que puedo dividirlo por años estrechos con:

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

Pero eso no me da los rangos de datos que quiero. ¿Cómo se puede hacer esto?

¿Fue útil?

Solución

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])

EDITAR - disculpas, estás en lo correcto. Aquí hay una versión fija (debería haber usado una tabla de prueba para comenzar ...)

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

Cambie las unidades con fecha si desea más granularidad que días.

EDIT # 2 - ok, aquí hay una solución más robusta que maneja los años bisiestos :) EDITAR # 3: en realidad, esto no maneja los años bisiestos, sino que permite especificar intervalos de tiempo variables. Vaya con dateadd (año, 1, @baseDate) para el enfoque seguro del año bisiesto.

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

Otros consejos

Si puede encontrar una manera de definir sus rangos de fechas en una tabla separada, seleccione una etiqueta y dos columnas de fechas y únase a eso desde su consulta principal, algo como esto dependiendo de sus tablas.

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
Licenciado bajo: CC-BY-SA con atribución
No afiliado a StackOverflow
scroll top