2011-05-26 12 views
5

En mi consulta sql, cuento el número de pedidos en cada hora del día. Mi consulta es como la siguiente:Todas las horas del día

SELECT COUNT(dbo.Uputa.ID),{ fn HOUR(dbo.Orders.Date) } AS Hour 
FROM  Orders  
WHERE dbo.Orders.Date BETWEEN '2011-05-01' AND '2011-05-26' 
GROUP BY { fn HOUR(dbo.Orders.Date) } 
ORDER BY Hour 

Mi problema es que la consulta devuelve horas solamente existen en dbo.Orders.Date.
Por ejemplo:

Number Hour 
12   3 
12   5 

quiero devolver todas las horas de la siguiente manera:

Number  Hour 
    0   0 
    0   1 
    0   2 
    12   3 
    0   4 
    12   5 
    ... 
    0   23 

¿Alguien tiene idea de cómo lograr esto?

Respuesta

6

Utilice una expresión de tabla común para crear todas las horas, luego a la izquierda unirse a sus totales agrupados para obtener un resultado. 'Tabla de números'

with mycte as 
(
    SELECT 0 AS MyHour 
    UNION ALL 
    SELECT MyHour + 1 
    FROM mycte 
    WHERE MyHour + 1 < 24 
) 
SELECT mycte.MyHour, COALESCE(OrderCount,0) FROM mycte 
LEFT JOIN 
(
    SELECT COUNT(dbo.Uputa.ID) AS OrderCount,{ fn HOUR(dbo.Orders.Date) } AS MyHour 
    FROM Orders  
    WHERE dbo.Orders.Date BETWEEN '2011-05-01' AND '2011-05-26' 
    GROUP BY { fn HOUR(dbo.Orders.Date) } 
) h 
ON 
    h.MyHour = mycte.MyHour; 
+0

no positivo del sql-server sintaxis al crear ese mycte, pero la teoría suena correcta ... – DRapp

+0

La parte CTE fue verificada antes de que subiera la respuesta. Parece que funcionó: D –

0

Puede agregar CTE para agregar las horas faltantes y JOIN éstas con su consulta original para completar los espacios en blanco.

instrucción SQL

;WITH q (Number, Hour) AS (
    SELECT 0, 1 
    UNION ALL 
    SELECT q.Number, q.Hour + 1 
    FROM q 
    WHERE q.Hour < 23 
) 
SELECT COALESCE(o.Number, q.Number) 
     , q.Hour 
FROM q 
     LEFT OUTER JOIN (
      SELECT COUNT(dbo.Uputa.ID),{ fn HOUR(dbo.Orders.Date) } AS Hour 
      FROM  Orders  
      WHERE dbo.Orders.Date BETWEEN '2011-05-01' AND '2011-05-26' 
      GROUP BY { fn HOUR(dbo.Orders.Date) } 
     ) o ON o.Hour = q.Hour 
ORDER BY 
     q.Hour  

script de prueba

;WITH Orders (Number, Hour) AS (
    SELECT 12, 3 
    UNION ALL SELECT 12, 5 
) 
, q (Number, Hour) AS (
    SELECT 0, 1 
    UNION ALL 
    SELECT q.Number, q.Hour + 1 
    FROM q 
    WHERE q.Hour < 23 
) 
SELECT COALESCE(o.Number, q.Number) 
     , q.Hour 
FROM q 
     LEFT OUTER JOIN Orders o ON o.Hour = q.Hour 
1

A (SQL, Auxiliary table of numbers por ejemplo) es en general una cosa bastante útil para tener en su base de datos; si creas uno aquí, puedes seleccionar todas las filas entre 0 y 23 de tu tabla de números, unirlas a tus resultados y obtendrás los resultados que desees sin la necesidad de crear un CTE personalizado o similar solo para esta consulta.

SELECT COUNT(dbo.Uputa.ID),n.number AS Hour 
FROM  (select number from numbers where number between 0 and 23) n 
      left join Orders o on n.number={ fn HOUR(dbo.Orders.Date) } 
WHERE dbo.Orders.Date BETWEEN '2011-05-01' AND '2011-05-26' 
GROUP BY n.number 
ORDER BY n.number 

(he redactado este como por su ejemplo para mayor claridad, pero en la práctica que iba a tratar y evitar poner en función de los criterios de unión para maximizar el rendimiento.)

Cuestiones relacionadas