2009-02-26 14 views
5

Utilizzo MS SQL Server ma accolgo con favore soluzioni comparative da altri database.Come includere righe vuote in una query SQL GROUP BY DAY (data_field) singola?

Questa è la forma base della mia richiesta. Si restituisce il numero di chiamate al giorno dal tavolo 'incidentsm1':

SELECT 
    COUNT(*) AS "Calls", 
    MAX(open_time), 
    open_day 
FROM 
    (
SELECT 
incident_id, 
opened_by, 
open_time - (9.0/24) AS open_time, 
DATEPART(dd, (open_time-(9.0/24))) AS open_day 
    FROM incidentsm1 
    WHERE 
DATEDIFF(DAY, open_time-(9.0/24), GETDATE())< 7 

) inc1 
GROUP BY open_day 

Questi dati vengono usati per disegnare un grafico a barre, ma se non ci fossero le chiamate in un determinato giorno della settimana, non v'è alcun risultato riga e quindi nessuna barra, e l'utente è come, "perché il grafico ha solo sei giorni e salta da sabato a lunedì?"

In qualche modo ho bisogno di UNION ALL con una riga vuota da ogni giorno o qualcosa del genere, ma non riesco a capirlo.

Sono limitato a ciò che posso fare con una sola istruzione SQL e ho accesso in sola lettura, quindi non posso creare una tabella temporanea o altro.

+0

Basta aggiungerlo nel tuo livello di interfaccia utente. http://stackoverflow.com/questions/346659/what-are-the-most-common-sql-anti-patterns/346850#346850 –

+0

scusate, lo farei, ma è impossibile con lo stravagante strumento commerciale che mi viene richiesto uso. – Nathan

risposta

7

Che ne dici di qualcosa di simile?

SELECT 
    COUNT(incident_id) AS "Calls", 
    MAX(open_time), 
    days.open_day 
FROM 
(
    select datepart(dd,dateadd(day,-6,getdate())) as open_day union 
    select datepart(dd,dateadd(day,-5,getdate())) as open_day union 
    select datepart(dd,dateadd(day,-4,getdate())) as open_day union 
    select datepart(dd,dateadd(day,-3,getdate())) as open_day union 
    select datepart(dd,dateadd(day,-2,getdate())) as open_day union 
    select datepart(dd,dateadd(day,-1,getdate())) as open_day union 
    select datepart(dd,dateadd(day, 0,getdate())) as open_day 
) days 
left join 
(
SELECT 
    incident_id, 
    opened_by, 
    open_time - (9.0/24) AS open_time, 
    DATEPART(dd, (open_time-(9.0/24))) AS open_day 
FROM incidentsm1 
WHERE DATEDIFF(DAY, open_time-(9.0/24), GETDATE()) < 7 
) inc1 ON days.open_day = incidents.open_day 
GROUP BY days.open_day 

L'ho provato solo su uno schema di tabella semplificato, ma penso che dovrebbe funzionare. Potrebbe essere necessario armeggiare con la roba dateadd ..

+0

GRAZIE! Speravo in qualcosa di più lento, ma posso addormentare 7 righe per creare un calendario virtuale. NB, ho dovuto aggiungere una clausola 'ON' al iscriverti per farlo funzionare: ) INC1 ON days.open_day = incidents.open_day GROUP BY days.open_day BTW, è NZ dove il selvaggio Le cose sono? – Nathan

+0

oops grazie, risolto. Sì, abbiamo dei viziosi .. tuataras .. e grandi .. kiwi .. sì. – Blorgbeard

+0

Sei il mio eroe. – Nathan

0

È possibile creare una variabile di tabella con le date necessarie e quindi RIGHT JOIN su di esso? Ad esempio,

DECLARE @dateTable TABLE ([date] SMALLDATETIME) 

INSERT INTO @dateTable 
VALUES('26 FEB 2009') 
INSERT INTO @dateTable 
VALUES('27 FEB 2009') 
-- etc 

SELECT 
    COUNT(*) AS "Calls", 
    MAX(open_time), 
    open_day 
FROM 
    (
SELECT 
incident_id, 
opened_by, 
open_time - (9.0/24) AS open_time, 
DATEPART(dd, (open_time-(9.0/24))) AS open_day 
    FROM incidentsm1 
    RIGHT JOIN @dateTable dates 
    ON incidentsm1.open_day = dates.date 
    WHERE 
DATEDIFF(DAY, open_time-(9.0/24), GETDATE())< 7 

) inc1 
GROUP BY open_day 

La situazione più ideale però, sarebbe quello di avere un oggetto tabella con le date in

+0

Posso usare solo un'istruzione SQL, quindi sembra che possa anteporre "DECLARE" ma non posso inserire i dati nella mia istruzione SELECT. – Nathan

0

vorrei suggerire l'utilizzo di un date table. Con una tabella data esistente, puoi eseguire un GIUNTO ESTERNO GIUSTO alla tabella della data per inserire i giorni mancanti.

+0

mi spiace, ho solo accesso in sola lettura. Potrei ricorrere a una colonna di date, sono sicuro che avrà sempre un valore per ogni giorno, ma sembra che ci dovrebbe essere un modo migliore. – Nathan

0

È possibile creare l'insieme di date come parte della query? Qualcosa sulla falsariga di:

SELECT COUNT(*) AS Calls, ... 
    FROM incidentsm1 RIGHT OUTER JOIN 
     (SELECT date_values 
      FROM TABLE(('27 Feb 2009'), ('28 Feb 2009'), ('1 Mar 2009'), 
         ('2 Mar 2009'), ('3 Mar 2009'), ('4 Mar 2009'), 
         ('5 Mar 2009')) AS date_list 
     ) 
     ON ... 

Questo è ispirata da una sorta di ibrido tra Informix e notazioni DB2 ed è praticamente garantito per essere sintatticamente corretta in entrambi. Fondamentalmente, c'è un modo nel tuo DBMS di creare una tabella letterale al volo. Una possibilità - brutta ma a malapena fattibile - sarebbe quella di fare un UNION di 7 letterali di data selezionato da "doppio" o qualche espressione di tabella che garantisce una riga (in termini Informix, SELECT MDY(2,28,2009) FROM "informix".systables WHERE tabid = 1 UNION ...).

+0

Non c'è DUAL in MSSQL, sebbene possa ancora avere fortuna usando 'WITH' (http://technet.microsoft.com/en-us/library/ms175972(SQL.90).aspx) ... Inoltre, ho bisogno questa query deve essere eseguita regolarmente, quindi non posso eseguire l'hardcode delle date ma devo calcolarle in qualche modo, probabilmente come 'DATEADD (DAY, -1, GETDATE())' – Nathan

+0

Abbastanza corretto; in Informix, che sarebbe TODAY - 1, ecc ... –

+0

Nota, non c'è bisogno di DUAL in mssql, dato che non hai bisogno di una clausola from - per quanto riguarda la mia comprensione di DUAL va :) – Blorgbeard