2009-08-13 43 views
7

我有一个电子商务商店中的订单信息表。模式是这样的:每天从SQL DB中选择数据

[常规]
ID |小计| TAXAMOUNT | ShippingAmount | dateCreated会

此表并只包含数据,每一份订单。所以如果一天没有订单,那么当天就没有销售数据。

我想选择过去30天的小计,包括那些没有销售的日子。

结果集看起来像这样:

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

这样做,只让我对那些天的数据与命令:

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

您可以创建一个表中调用日期,并从该表中选择并加入Orders表。但我真的想避免这种情况,因为在处理不同的时区和事物时,它不够好...

请不要笑。 SQL是不是我的东西... :)

+0

你在使用?如果你使用MySQL或SQL Server,还是其他什么东西?答案可能会有所不同 – AnonJr 2009-08-13 20:40:39

+0

我使用MS SQL Server的 – MartinHN 2009-08-13 20:42:33

回答

2

创建可以生成日期表中的功能如下:
(从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 

然后,加入该表

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

稍微修改了Select语句,它的工作原理如下: SELECT dates.date,ISNULL(SUM(ordersubtotal),0)as Sales FROM [ dbo]。[DateTable]('2009-08-01','2009-08-31','day')datesLEFT JOIN Orders ON CONVERT(VARCHAR(10),Orders.datecreated,111)= dates.dategroup by dates .date – MartinHN 2009-08-13 21:10:58

+0

我更新了第二个查询。我在select/group by中输入了错误的日期字段,因此仅限于销售日期。我测试了这个版本,我认为它给出了你想要的。对于没有销售的日子,它具有NULL而不是0,但是您可以轻松使用COALESCE函数将其清除。 – JamesMLV 2009-08-13 21:11:36

+0

我不能得到这个工作的奶酪。有人能告诉我确切的正确答案吗? – philbird 2011-05-29 13:48:32

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 

好的 - 我错过了'过去30天'的一部分。上面的一点,虽然不是干净的,恕我直言,作为日期表,应该工作。另一个变体是使用while循环来填充临时表,最近30天,并使用我原始查询的结果执行左外连接。

+0

只需添加一个WHERE子句过去30天 – jdelator 2009-08-13 20:17:05

+4

这将不包括任何日子,不要”没有任何销售(如最初要求) – scwagner 2009-08-13 20:19:45

+0

如果只是这么简单:)我需要每一天,在过去的30天。 – MartinHN 2009-08-13 20:20:51

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

包括没有销售那些日子。

这是困难的部分。我不认为第一个答案会帮助你。我用一个单独的日期表做了类似的事情。

你可以找到关于如何做到这一点这里的方向:

Date Table

+0

其实,我是在假设没有销售的日子不会在桌子上。如果不是,不理我的答案。 – DavidStein 2009-08-13 20:20:29

+0

它不是。该表只包含每个订单的数据。因此,如果一天没有订单,那么当天就没有销售数据。 – MartinHN 2009-08-13 20:23:39

+1

然后,我将创建一个包含所有日期的日期表,然后执行左连接以查询每日总结销售额。您还会记得在没有销售的情况下使用coalesce语句来返回零而不是null。我必须在许多不同的情况下做到这一点,外部日期表是要走的路。 – DavidStein 2009-08-13 20:27:43

0

我今天真的这样做过。我们还有一个电子商务应用程序。我不想在我们的数据库中填入“无用的”日期。我只是做了一个小组,并创建了Java中最后N天的所有日子,并将它们与数据库中的日期/销售结果进行同步。

0

这最终会在哪里结束?我只问,因为用任何程序来处理数据,而不是试图用SQL来完成空填充空的日子可能会更容易。

SQL是一个美妙的语言,它是能够在许多伟大的事情,但有时你只是更好的工作数据的细微之处的节目代替。

1

我有LOGID日志表的表,我从来没有删除任何记录的索引。它的索引从1到〜10000000。使用这个表,我可以写

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

(修改了一下 - 我打得太很快进入)

我开始在这个戳,并且因为它击中了一些相当棘手的SQL概念也迅速成长为以下怪物。如果可行,你可能会更适应THEn的解决方案;或者像其他许多人一样建议,使用应用程序代码填补空白可能是可取的。

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

第1步是建立一个临时表包含您关心的30个日期。这种抽象的奇怪是关于建立一个连续整数表的最快方式;添加几个子查询,并且可以在几秒钟内填充数百万或更多。我拿第30个,并使用dateadd和当前日期/时间将它们转换为日期。如果你已经有一个1-30的“固定”表,你可以使用它并完全跳过CTE(用你的表替换表“Tally”)。

外部两个日期函数调用删除生成的字符串的时间部分。

(请注意,我假设你的订单日期也没有时间部分 - 否则,你就必须解决另一个常见的问题。)

出于测试目的,我建表#Orders,这可以让你的休息:

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

这是基于SQL Server 2005的,其中引入了公用表表达式(即丑陋的“WITH”子句)。还有其他方法可以获得这些结果,但CTE对于临时标记表格构建来说是最快的。 – 2009-08-13 21:08:12

0

我创建的功能DateTable作为JamesMLV向我指出。

然后是SQL看起来是这样的:

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