2009-02-26 21 views
5

Używam MS SQL Server, ale przyjmuję rozwiązania porównawcze z innych baz danych.Jak uwzględnić puste wiersze w jednym zapytaniu SQL GROUP BY DAY (date_field)?

To jest podstawowa forma mojego zapytania. Zwraca liczbę połączeń dziennie z „incidentsm1” tabela:

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 

Dane te są wykorzystywane do narysować wykres słupkowy, ale gdyby nie było rozmowy na dany dzień tygodnia, nie ma wynik wiersz, a więc bez paska, a użytkownik jest jak "dlaczego wykres ma tylko sześć dni i przeskoczyć od soboty do poniedziałku?"

W jakiś sposób potrzebuję UNIONA WSZYSTKIEGO z pustym wierszem z każdego dnia lub czegoś podobnego, ale nie mogę tego rozgryźć.

Jestem ograniczony do tego, co mogę zrobić z jednym oświadczeniem SQL i mam dostęp tylko do odczytu, więc nie mogę utworzyć tabeli tymczasowej ani nic.

+0

Wystarczy dodać go do warstwy interfejsu użytkownika. http://stackoverflow.com/questions/346659/what-are-the-most-common-sql-anti-patterns/346850#346850 –

+0

Przepraszam, zrobiłabym to, ale nie jest to możliwe z fantazyjnym narzędziem komercyjnym, do którego jestem zobowiązany posługiwać się. – Nathan

Odpowiedz

7

Co powiesz na coś takiego?

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 

Testowałem go tylko na uproszczonym schemacie tabeli, ale myślę, że powinien zadziałać. Być może będziesz musiał majstrować przy materiałach dateadd ..

+0

DZIĘKUJEMY! Miałem nadzieję na coś w rodzaju pętli, ale mogę znieść 7 linii, by stworzyć wirtualny stół z datami. NB, musiałem dodać klauzulę 'ON' do przyłączenia się zmusić go do pracy: ) INC1 NA days.open_day = incidents.open_day GROUP BY days.open_day BTW Czy NZ gdzie dziki rzeczy są? – Nathan

+0

oops dzięki, naprawione. Tak, mamy błędne .. tuataras .. i wielkie duże .. Kiwi .. tak. – Blorgbeard

+0

Jesteś moim bohaterem. – Nathan

0

Czy można utworzyć zmienną tabeli z datami, które są potrzebne, a następnie RIGHT JOIN? Na przykład,

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 

Im bardziej sytuacja idealna jednak byłoby mieć obiektu tabela z datami w

+0

Mogę używać tylko jednej instrukcji SQL, więc wygląda na to, że mogę poprzedzić 'DECLARE', ale nie mogę wstawić danych do mojej instrukcji SELECT. – Nathan

0

Sugerowałbym użycie w date table. Przy istniejącej tabeli daty możesz wykonać DOŁĄCZ DO PRAWYM ZEWNĘTRZNYM do tabeli dat, aby wprowadzić brakujące dni.

+0

Niestety, mam dostęp tylko do odczytu. Mogę uciekać się do dołączenia do kolumny z datą, ale jestem pewien, że zawsze będzie mieć wartość na każdy dzień, ale wydaje się, że powinien istnieć lepszy sposób. – Nathan

0

Czy możesz utworzyć zestaw dat jako część zapytania? Coś wzdłuż linii:

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 ... 

To jest inspirowana przez pewnego rodzaju hybrydę Informix i notacje DB2 i jest dość dużo gwarancją niepoprawny składniowo w obu. Zasadniczo, w systemie DBMS istnieje sposób na stworzenie dosłownego stołu w locie. Jedną z możliwości - brzydką, ale ledwo wykonalną - byłoby zrobienie 7-way UNION literałów daty wybranych z "podwójnego" lub jakiegoś wyrażenia tabelowego, które gwarantuje jeden wiersz (w informixach, SELECT MDY(2,28,2009) FROM "informix".systables WHERE tabid = 1 UNION ...).

+0

Nie ma DUAL w MSSQL, choć nadal mogę mieć szczęście używając 'WITH' (http://technet.microsoft.com/en-us/library/ms175972(SQL.90).aspx) ... Również potrzebuję to zapytanie uruchamiać regularnie, więc nie mogę zakodować dat, ale muszę je jakoś obliczyć, prawdopodobnie tak jak 'DATEADD (DAY, -1, GETDATE())' – Nathan

+0

Wystarczająco fair; w Informix, to byłoby DZISIAJ - 1, etc ... –

+0

Uwaga, nie ma potrzeby stosowania DUAL w mssql, ponieważ nie potrzebujesz klauzuli from - o ile rozumiem DUAL :) – Blorgbeard