2008-11-30 17 views
14

Tengo una tabla de SQL 2005, vamos a llamarlo Órdenes, en el formato:SQL por día, muestran pedidos de cada día

OrderID, OrderDate, OrderAmount 
1,  25/11/2008, 10 
2,  25/11/2008, 2 
3,  30/1002008, 5 

entonces necesito para producir una tabla de informe que muestra la cantidad ordenada en cada días en los últimos 7 días:

Day,  OrderCount, OrderAmount 
25/11/2008, 2,   12 
26/11/2008, 0,   0 
27/11/2008, 0,   0 
28/11/2008, 0,   0 
29/11/2008, 0,   0 
30/11/2008, 1,   5 

La consulta SQL que normalmente produciría esto:

select count(*), sum(OrderAmount) 
    from Orders 
    where OrderDate>getdate()-7 
    group by datepart(day,OrderDate) 

tiene un problema en que se saltará los días en que no hay órdenes:

Day,  OrderCount, OrderAmount 
25/11/2008, 2,   12 
30/11/2008, 1,   5 

Normalmente habría solucionar este problema utilizando una tabla de conteo y la combinación externa contra filas allí, pero estoy realmente en busca de una solución más simple o más eficiente para este . Parece un requisito tan común para una consulta de informe que alguna solución elegante ya debería estar disponible para esto.

Entonces: 1. ¿Se puede obtener este resultado de una consulta simple sin usar tablas de conteo?

y 2. Si no, ¿podemos crear esta tabla de conteo (confiablemente) sobre la marcha (puedo crear una tabla de conteo usando CTE pero la pila de recursión me limita a 100 filas)?

+0

Su ejemplo SELECT omite la información de fecha. –

+5

SQL grupo por día, escuadrón de lucha contra el crimen por la noche –

+0

Este enlace contiene información completa sobre la agrupación de datos por día - día del mes - día de la semana - día del año en detalle con exaples. http://sqlserverlearner.com/2012/group-by-day-with-examples –

Respuesta

0

Dependiendo de cómo SQL Server maneje las tablas temporales, puede organizar más o menos fácilmente la creación de una tabla temporal y llenarla con las 7 (¿o fueron las 8?) Fechas que le interesan. Puede usar eso como tu tabla de recuento No hay una manera más limpia que yo sepa; solo puede seleccionar los datos que existen en una tabla o que pueden derivarse de los datos que existen en una tabla o conjunto de tablas. Si hay fechas no representadas en la tabla Pedidos, no puede seleccionar esas fechas en la tabla Pedidos.

10

SQL no está "omitiendo" fechas ... porque las consultas se ejecutan contra datos que están realmente en la tabla. Entonces, si no tiene un DATE en la tabla para el 14 de enero, entonces ¿por qué SQL le mostraría un resultado :)

Lo que necesita hacer es crear una tabla temporal y UNIRSE a ella.

CREATE TABLE #MyDates (TargetDate DATETIME) 
INSERT INTO #MyDates VALUES CONVERT(DATETIME, CONVERT(VARCHAR, GETDATE() - 0, 101)) 
INSERT INTO #MyDates VALUES CONVERT(DATETIME, CONVERT(VARCHAR, GETDATE() - 1, 101)) 
INSERT INTO #MyDates VALUES CONVERT(DATETIME, CONVERT(VARCHAR, GETDATE() - 2, 101)) 
INSERT INTO #MyDates VALUES CONVERT(DATETIME, CONVERT(VARCHAR, GETDATE() - 3, 101)) 
INSERT INTO #MyDates VALUES CONVERT(DATETIME, CONVERT(VARCHAR, GETDATE() - 4, 101)) 
INSERT INTO #MyDates VALUES CONVERT(DATETIME, CONVERT(VARCHAR, GETDATE() - 5, 101)) 
INSERT INTO #MyDates VALUES CONVERT(DATETIME, CONVERT(VARCHAR, GETDATE() - 6, 101)) 
INSERT INTO #MyDates VALUES CONVERT(DATETIME, CONVERT(VARCHAR, GETDATE() - 7, 101)) 

SELECT CONVERT(VARCHAR, TargetDate, 101) AS Date, COUNT(*) AS OrderCount 
FROM dbo.Orders INNER JOIN #MyDates ON Orders.Date = #MyDates.TargetDate 
GROUP BY blah blah blah (you know the rest) 

¡Aquí lo tiene!

0

Como querrá usar esta tabla de fechas frecuentemente en otras consultas, le sugiero que la haga una tabla permanente y cree un trabajo para agregar las fechas de año nuevo una vez al año.

+0

O rellene una vez con 20 años de fechas. Tamaño trivial, y por qué preocuparse por el trabajo. El próximo año no se ejecutará y él se habrá ido ... – dkretz

1

Si desea ver el valor cero que poner la siguiente consulta:

select count(*), sum(OrderAmount) 
from Orders 
where OrderDate>getdate()-7 
    and sum(OrderAmount) > 0 or sum(OrderAmount) = 0 
group by datepart(day,OrderDate) 
2

que tenía el mismo problema y así es como lo resolví:

SELECT datename(DW,nDays) TimelineDays, 
    Convert(varchar(10), nDays, 101) TimelineDate, 
    ISNULL(SUM(Counter),0) Totals 
FROM (Select GETDATE() AS nDays 
    union Select GETDATE()-1 
    union Select GETDATE()-2 
    union Select GETDATE()-3 
    union Select GETDATE()-4 
    union Select GETDATE()-5 
    union Select GETDATE()-6) AS tDays 

Left Join (Select * From tHistory Where Account = 1000) AS History 
      on (DATEPART(year,nDays) + DATEPART(MONTH,nDays) + DATEPART(day,nDays)) = 
      (DATEPART(year,RecordDate) + DATEPART(MONTH,RecordDate) + DATEPART(day,RecordDate)) 
GROUP BY nDays 
ORDER BY nDays DESC 

que la salida es:

TimelineDays, TimelineDate,  Totals 

Tuesday   10/26/2010  0 
Monday   10/25/2010  6 
Sunday   10/24/2010  3 
Saturday  10/23/2010  2 
Friday   10/22/2010  0 
Thursday  10/21/2010  0 
Wednesday  10/20/2010  0 
0
CREATE PROCEDURE [dbo].[sp_Myforeach_Date] 
    -- Add the parameters for the stored procedure here 
    @SatrtDate as DateTime, 
    @EndDate as dateTime, 
    @DatePart as varchar(2), 
    @OutPutFormat as int 
AS 
BEGIN 
    -- SET NOCOUNT ON added to prevent extra result sets from 
    -- interfering with SELECT statements. 
    Declare @DateList Table 
    (Date varchar(50)) 

    WHILE @SatrtDate<= @EndDate 
    BEGIN 
    INSERT @DateList (Date) values(Convert(varchar,@SatrtDate,@OutPutFormat)) 
    IF Upper(@DatePart)='DD' 
    SET @SatrtDate= DateAdd(dd,1,@SatrtDate) 
    IF Upper(@DatePart)='MM' 
    SET @SatrtDate= DateAdd(mm,1,@SatrtDate) 
    IF Upper(@DatePart)='YY' 
    SET @SatrtDate= DateAdd(yy,1,@SatrtDate) 
    END 
    SELECT * FROM @DateList 
END 

Simplemente ponga este código y llamar al SP de esta manera

exec sp_Myforeach_Date @SatrtDate='03 Jan 2010',@EndDate='03 Mar 2010',@DatePart='dd',@OutPutFormat=106 

Gracias * Suvabrata Roy ICRA Online Ltd. Calcuta *