2009-07-23 13 views
9

Similar a this question, necesito agrupar una gran cantidad de registros en "depósitos" de 1 hora. Por ejemplo, digamos que tengo una tabla ORDEN típica con una fecha y hora adjunta a cada pedido. Y quiero ver el número total de pedidos por hora. Así que estoy usando SQL más o menos así:Agrupar/agregar resultados SQL en intervalos de 1 hora

SELECT datepart(hh, order_date), SUM(order_id) 
FROM ORDERS 
GROUP BY datepart(hh, order_date) 

El problema es que si no hay órdenes en una 1 hora de "cubo" dado, ninguna fila se emite en el conjunto de resultados. Me gustaría que el conjunto de resultados tenga una fila para cada una de las 24 horas, pero si no se hicieron pedidos durante una hora en particular, simplemente registre el número de pedidos como O.

¿Hay alguna manera de hacerlo en una consulta única?

Véase también Getting Hourly Statistics Using SQL.

+0

Ayudaría saber qué versión de Pg está utilizando. –

Respuesta

7

Necesita tener una tabla precompilada (o una función que devuelve un conjunto de resultados de la tabla) para unirse, que contiene todas las ranuras de 1 hora que desea en el resultado.

Luego haces un OUTER JOIN con eso, y deberías obtenerlos todos.

Algo como esto:

SELECT SLOT_HOUR, SUM(order_id) 
FROM 
    ONEHOURSLOTS 
    LEFT JOIN ORDERS ON DATEPART(hh, order_date) = SLOT_HOUR 
GROUP BY SLOT_HOUR 
+0

Creo que también podría reemplazar 'ONEHOURSLOTS' con algo como' (seleccione 0 como SLOT_HOUR unión seleccione 1 como SLOT_HOUR unión ..) '- solo si usted estaba muerto configurado para mantenerlo en una sola consulta, aunque - puaj: P – Blorgbeard

+0

Usted podría hacer eso incluso más fácil generate_series() del usuario() (suponiendo que estés en postgres, que las etiquetas dicen que eres, pero la consulta de ejemplo no funcionaría allí ...) –

2

Crear una tabla de horas, o bien persistió o incluso sintetiza 'sobre la marcha':

SELECT h.hour, s.sum 
FROM (
    SELECT 1 as hour 
    UNION ALL SELECT 2 
    UNION ALL SELECT 3 
    ... 
    UNION ALL SELECT 24) as h 
LEFT OUTER JOIN (
    SELECT datepart(hh, order_date) as hour, SUM(order_id) as sum 
     FROM ORDERS 
     GROUP BY datepart(hh, order_date)) as s 
    ON h.hour = s.hour; 
8

Algunas de las respuestas anteriores Recomienda el uso de una tabla de horas y poblarlo usando una consulta UNION; esto se puede hacer mejor con una Expresión de tabla común:

; WITH [Hours] ([Hour]) AS 
(
SELECT TOP 24 ROW_NUMBER() OVER (ORDER BY [object_id]) AS [Hour] 
FROM sys.objects 
ORDER BY [object_id] 
) 
SELECT h.[Hour], o.[Sum] 
FROM [Hours] h 
LEFT OUTER JOIN (
    SELECT datepart(hh, order_date) as [Hour], SUM(order_id) as [Sum] 
     FROM Orders 
     GROUP BY datepart(hh, order_date) 
) o 
ON h.[Hour] = o.[Hour] 
+0

+1 para el truco sys.objects. Algún día enviarán una versión que solo muestra objetos de usuario con acceso en sys.objects y mover objetos del sistema a sys.all_objects, pero para arruinar tus guiones lol –

+0

Afortunadamente, esa será la versión que tenga una tabla de números (http : //sqlserver2000.databases.aspfaq.com/why-should-i-consider-using-an-auxiliary-numbers-table.html) en él, por lo que no necesitará hacks como este –

Cuestiones relacionadas