2009-08-13 21 views
7

Tengo una tabla con información de pedido en una tienda de comercio electrónico. Esquema es el siguiente:Seleccionar datos de SQL DB por día

[Ordenes]
Id | Subtotal | TAXAMOUNT | ShippingAmount | DateCreated

Esta tabla no sólo contienen datos para cada orden. Entonces, si pasa un día sin pedidos, no hay datos de ventas para ese día.

Me gustaría seleccionar el subtotal por día durante los últimos 30 días, incluidos los días sin ventas.

El conjunto de resultados se vería así:

Fecha | SalesSum
2009-08-01 | 15235
2009-08-02 | 0
2009-08-03 | 340
2009-08-04 | 0
...

Al hacer esto, sólo me da datos para esos días con las órdenes:

select DateCreated as Date, sum(ordersubtotal) as SalesSum 
from Orders 
group by DateCreated 

Se puede crear una tabla llamada fechas y seleccione alguna de que la mesa y se unen a la tabla Pedidos. Pero realmente quiero evitar eso, porque no funciona lo suficientemente bien cuando se trata de diferentes zonas horarias y cosas ...

Por favor, no te rías. SQL no es mi tipo de cosa ... :)

+0

¿Qué estás usando? Las respuestas pueden variar si está usando MySQL, SQL Server u otra cosa ... – AnonJr

+0

Estoy usando el servidor MS SQL – MartinHN

Respuesta

2

crear una función que puede generar una tabla de fechas de la siguiente manera:
(robado de http://www.codeproject.com/KB/database/GenerateDateTable.aspx)

Create Function dbo.fnDateTable 
(
    @StartDate datetime, 
    @EndDate datetime, 
    @DayPart char(5) -- support 'day','month','year','hour', default 'day' 
) 
Returns @Result Table 
(
    [Date] datetime 
) 
As 
Begin 
    Declare @CurrentDate datetime 
    Set @[email protected] 
    While @CurrentDate<[email protected] 
    Begin 
    Insert Into @Result Values (@CurrentDate) 
    Select @CurrentDate= 
    Case 
    When @DayPart='year' Then DateAdd(yy,1,@CurrentDate) 
    When @DayPart='month' Then DateAdd(mm,1,@CurrentDate) 
    When @DayPart='hour' Then DateAdd(hh,1,@CurrentDate) 
    Else 
     DateAdd(dd,1,@CurrentDate) 
    End 
    End 
    Return 
End 

Luego, únase a esa tabla

SELECT dates.Date as Date, sum(SubTotal+TaxAmount+ShippingAmount) 
FROM [fnDateTable] (dateadd("m",-1,CONVERT(VARCHAR(10),GETDATE(),111)),CONVERT(VARCHAR(10),GETDATE(),111),'day') dates 
LEFT JOIN Orders 
ON dates.Date = DateCreated 
GROUP BY dates.Date 
+0

Con una declaración Select ligeramente modificada, funciona: SELECCIONAR fechas.date, ISNULL (SUMA (ordersubtotal), 0) como Sales FROM [ dbo]. [DateTable] ('2009-08-01', '2009-08-31', 'day') datesLEFT UNIR Pedidos ON CONVERTIR (VARCHAR (10), Pedidos.datecreated, 111) = fechas.dategrupo por fechas .date – MartinHN

+0

He actualizado la segunda consulta. Tenía el campo de fecha incorrecta en la selección/grupo por, por lo que se limitó a solo las fechas con ventas. Probé esta versión, y creo que da lo que quieres. Tiene NULLs en lugar de 0s durante días sin ventas, pero puede usar fácilmente la función COALESCE para borrarlos. – JamesMLV

+0

No puedo hacer que esto funcione para el queso. ¿Puede alguien mostrarme la respuesta correcta exacta? – philbird

2
declare @oldest_date datetime 
declare @daily_sum numeric(18,2) 
declare @temp table(
    sales_date datetime, 
    sales_sum numeric(18,2) 
) 
select @oldest_date = dateadd(day,-30,getdate()) 

while @oldest_date <= getdate() 
begin 
    set @daily_sum = (select sum(SubTotal) from SalesTable where DateCreated = @oldest_date) 
    insert into @temp(sales_date, sales_sum) values(@oldest_date, @daily_sum) 
    set @oldest_date = dateadd(day,1,@oldest_date) 
end 

select * from @temp 

OK - Me perdí esa parte de los "últimos 30 días". El bit de arriba, aunque no tan limpio, en mi humilde opinión, como la tabla de fechas, debería funcionar. Otra variante sería usar el ciclo while para completar una tabla temporal solo en los últimos 30 días y hacer una combinación externa izquierda con el resultado de mi consulta original.

+0

Solo agregue una cláusula Where en los últimos 30 días – jdelator

+4

Esto no incluirá los días que no lo hagan t tiene cualquier venta en ellos (como se solicitó originalmente) – scwagner

+0

Si fue así de fácil :) Necesito todos los días, durante los últimos 30 días. – MartinHN

-1
SELECT DateCreated, 
SUM(SubTotal) AS SalesSum 
FROM Orders 
GROUP BY DateCreated 
1

incluyendo aquellos días sin ventas.

Esa es la parte difícil. No creo que la primera respuesta te ayude con eso. Hice algo similar a esto con una tabla de fechas separada.

Puede encontrar las instrucciones de cómo hacerlo aquí:

Date Table

+0

En realidad, estaba bajo la suposición de que días sin ventas no estarían en la mesa. Si no, ignora mi respuesta. – DavidStein

+0

No lo es. La tabla solo contiene datos por pedido. Entonces, si pasa un día sin pedidos, no hay datos de ventas para ese día en particular. – MartinHN

+1

Luego crearía una tabla de fechas con todas las fechas y luego unirme a la izquierda para una consulta que resumiría las ventas por día. También recordaría usar una declaración de coalescencia para devolver cero en lugar de nulo durante días sin ventas. Tuve que hacer esto en muchas situaciones diferentes y la tabla de fechas externa fue el camino a seguir. – DavidStein

0

De hecho lo hice hoy. También obtuvimos una aplicación de comercio electrónico. No quiero llenar nuestra base de datos con fechas "inútiles". Solo hago el grupo y creo todos los días de los últimos N días en Java y los comparo con los resultados de fecha/ventas de la base de datos.

0

¿Dónde terminará esto finalmente? Solo pregunto porque puede ser más fácil completar los días vacíos con cualquier programa que vaya a tratar con los datos en lugar de tratar de hacerlo en SQL.

SQL es un lenguaje maravilloso, y es capaz de muchas cosas, pero a veces es mejor que trabajes los puntos más finos de los datos en el programa.

1

Tengo una tabla de tabla de registro con LogID, un índice que nunca borro ningún registro. tiene un índice de 1 a ~ 10000000. El uso de esta tabla que puedo escribir

select 
    s.ddate, SUM(isnull(o.SubTotal,0)) 
from 
    (
     select 
      cast(datediff(d,LogID,getdate()) as datetime) AS ddate 
     from 
      Log 
     where 
      LogID <31 
    ) s right join orders o on o.orderdate = s.ddate 
group by s.ddate 
0

(revisado un poco - me golpeó entrar demasiado pronto)

empecé a meter en esto, y como llega a algunos conceptos de SQL bastante difícil que se convirtió rápidamente en la siguiente monstruo. Si es factible, es mejor que adaptes la solución de THEn; o, como muchos otros aconsejan, podría ser preferible utilizar el código de la aplicación para completar los vacíos.

-- A temp table holding the 30 dates that you want to check 
DECLARE @Foo Table (Date smalldatetime not null) 

-- Populate the table using a common "tally table" methodology (I got this from SQL Server magazine long ago) 
;WITH 
    L0 AS (SELECT 1 AS C UNION ALL SELECT 1), --2 rows 
    L1 AS (SELECT 1 AS C FROM L0 AS A, L0 AS B),--4 rows 
    L2 AS (SELECT 1 AS C FROM L1 AS A, L1 AS B),--16 rows 
    L3 AS (SELECT 1 AS C FROM L2 AS A, L2 AS B),--256 rows 
    Tally AS (SELECT ROW_NUMBER() OVER(ORDER BY C) AS Number FROM L3) 
INSERT @Foo (Date) 
select dateadd(dd, datediff(dd, 0, dateadd(dd, -number + 1, getdate())), 0) 
from Tally 
where Number < 31 

El paso 1 es construir una tabla temporal que contenga las 30 fechas que le preocupan. Esa extrañeza abstracta es la manera más rápida conocida de construir una tabla de enteros consecutivos; agregue algunas más subconsultas, y puede poblar millones o más en cuestión de segundos. Tomo los primeros 30 y uso dateadd y la fecha/hora actual para convertirlos en fechas. Si ya tiene una tabla "fija" que tiene 1-30, puede usar eso y omitir el CTE por completo (reemplazando la tabla "Tally" con su tabla).

Las dos llamadas a la función de fecha externa eliminan la porción de tiempo de la cadena generada.

(Tenga en cuenta que asumir que su fecha de orden también tiene parte de tiempo - de lo contrario usted tiene otro problema común de resolver.)

Para propósitos de prueba he construido #Orders de mesa, y esto que el se Descanso:

SELECT f.Date, sum(ordersubtotal) as SalesSum 
from @Foo f 
    left outer join #Orders o 
    on o.DateCreated = f.Date 
group by f.Date 
+0

Esto se basa en SQL Server 2005, en el que se introdujeron expresiones de tabla comunes (esa cláusula "WITH" fea). Hay otras maneras de obtener estos resultados, pero el CTE es más rápido para compilaciones de tablas ad hoc. –

0

Creé la función DateTable como JamesMLV me indicó.

Y entonces el SQL tiene este aspecto:

SELECT dates.date, ISNULL(SUM(ordersubtotal), 0) as Sales FROM [dbo].[DateTable] ('2009-08-01','2009-08-31','day') dates 
LEFT JOIN Orders ON CONVERT(VARCHAR(10),Orders.datecreated, 111) = dates.date 
group by dates.date 
Cuestiones relacionadas