2009-02-26 15 views
5

Estoy usando MS SQL Server pero recibo soluciones comparativas de otras bases de datos.¿Cómo incluyo las filas vacías en una sola consulta SQL GROUP BY DAY (date_field)?

Esta es la forma básica de mi consulta. Devuelve el número de llamadas por día a partir de la tabla '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 

Estos datos son utilizados para dibujar un gráfico de barras, pero si no hay llamadas en un día determinado de la semana, no hay ningún resultado fila y, por lo tanto, no hay barra, y el usuario dice, "¿por qué el gráfico solo tiene seis días y se salta de sábado a lunes?"

De alguna manera necesito UNION TODO con una fila en blanco de cada día o algo así, pero no puedo resolverlo.

Estoy limitado a lo que puedo hacer con una declaración de SQL y tengo acceso de solo lectura, así que no puedo crear una tabla temporal ni nada.

+0

Simplemente agréguela a la capa de la interfaz de usuario. http://stackoverflow.com/questions/346659/what-are-the-most-common-sql-anti-patterns/346850#346850 –

+0

lo siento, lo haría, pero es imposible con la herramienta comercial de lujo que estoy obligado a utilizar. – Nathan

Respuesta

7

¿Qué tal algo así?

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 

Solo lo he probado en un esquema de tabla simplificado, pero creo que debería funcionar. Es posible que deba retocar las cosas de la fecha.

+0

¡GRACIAS! Esperaba algo más bucólico pero puedo soportar 7 líneas para hacer una tabla virtual de citas. NB, que tuvo que añadir una cláusula 'ON' al unirse a conseguir que funcione: ) INC1 EN days.open_day = incidents.open_day GROUP BY days.open_day Por cierto, es NZ, donde la naturaleza ¿las cosas son? – Nathan

+0

oops gracias, arreglado. Sí, tenemos viciosas ... tuataras ... y grandes ... kiwis ... sí. – Blorgbeard

+0

Eres mi héroe. – Nathan

0

¿Puedes crear una variable de tabla con las fechas que necesites y luego RIGHT JOIN en ella? Por ejemplo, sin embargo

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 situación más ideal, sería tener un objeto de tabla con las fechas en

+0

Solo puedo usar una declaración SQL, por lo que parece que puedo anteponer el 'DECLARE' pero no puedo insertar los datos en mi instrucción SELECT. – Nathan

0

Yo sugeriría el uso de un date table. Con una tabla de fechas existente en su lugar, puede realizar una DERECHA EXTERIOR ÚNASE a la tabla de fechas para traer sus días perdidos.

+0

lo siento, solo tengo acceso de solo lectura. Puedo recurrir a unirse a una columna de fecha. Estoy bastante seguro de que siempre tendrá un valor para cada día, pero parece que debería haber una mejor manera. – Nathan

0

¿Puedes crear el conjunto de fechas como parte de tu consulta? Algo a lo largo de las líneas de:

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

Esto se inspira en una especie de híbrido de Informix y DB2 notaciones y es más o menos garantiza que sea sintácticamente incorrecto en ambos. Básicamente, hay una manera en su DBMS de crear una tabla literal sobre la marcha. Una posibilidad, fea pero casi factible, sería hacer una UNIÓN de 7 vías de literales de fecha seleccionados de 'dual' o alguna expresión de tabla que garantice una fila (en términos de Informix, SELECT MDY(2,28,2009) FROM "informix".systables WHERE tabid = 1 UNION ...).

+0

No hay DUAL en MSSQL, aunque todavía puedo tener suerte usando 'WITH' (http://technet.microsoft.com/en-us/library/ms175972(SQL.90).aspx) ... También, necesito esta consulta se ejecuta regularmente, por lo que no puedo codificar las fechas, pero tengo que calcularlas de alguna manera, probablemente como 'DATEADD (DAY, -1, GETDATE())' – Nathan

+0

Bastante justo; en Informix, eso sería HOY - 1, etc ... –

+0

Nota, no hay necesidad de DUAL en mssql, ya que no necesita una cláusula from - en lo que respecta a mi comprensión de DUAL :) – Blorgbeard