2009-07-23 11 views
9

Analogamente a this question, è necessario raggruppare un numero elevato di record in "bucket" di un'ora. Ad esempio, supponiamo di avere una tabella ORDER tipica con un datetime allegato a ciascun ordine. E voglio vedere il numero totale di ordini all'ora. Così sto utilizzando SQL o meno così:Raggruppamento/aggregazione di risultati SQL in bucket di 1 ora

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

Il problema è che se non ci sono ordini in 1 ora di dato "secchio", nessuna riga viene emesso nel set di risultati. Mi piacerebbe che il set di risultati avesse una riga per ciascuna delle 24 ore, ma se non sono stati effettuati ordini durante un'ora specifica, registra il numero di ordini come O.

C'è un modo per farlo in un domanda singola?

Vedere anche Getting Hourly Statistics Using SQL.

+0

Sarebbe utile sapere quale versione di Pg si sta utilizzando. –

risposta

7

È necessario disporre di una tabella precompilata (o di una funzione che restituisce un set di risultati di tabella) da unire, che contenga tutte le posizioni di 1 ora desiderate nel risultato.

Poi fai un OUTER JOIN con quello, e dovresti averli tutti.

Qualcosa di simile a questo:

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

Credo che potresti anche sostituire 'ONEHOURSLOTS' con qualcosa di simile a' (seleziona 0 come unione SLOT_HOUR seleziona 1 come unione SLOT_HOUR ..) '- solo se sei morto imposta su mantenerlo in una singola query però - yuck: P – Blorgbeard

+0

You potrebbe farlo ancora più facile utente generate_series() (assumendo che tu sia su postgres, che i tag dicono di essere, ma la query di esempio non funzionerebbe lì ..) –

2

Creare una tabella di ore, sia persistito o addirittura sintetizzata 'al volo':

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

Alcune delle risposte precedenti consiglia di utilizzare una tabella di ore e popolarlo usando una query UNION; questo può essere fatto meglio con un'espressione di tabella comune:

; 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 per il trucco sys.objects. Un giorno spediranno una versione che mostra solo oggetti utente con accesso in sys.objects e sposta gli oggetti di sistema in sys.all_objects, jut per rovinare i tuoi script lol –

+0

Speriamo che questa sia la versione che ha una tabella di numeri (http : //sqlserver2000.databases.aspfaq.com/why-should-i-consider-using-an-auxiliary-numbers-table.html), quindi non avrai bisogno di hack come questo –

Problemi correlati