2009-08-13 69 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