2009-08-13 35 views
7

Tôi có một bảng có thông tin đơn đặt hàng trong một cửa hàng Thương mại điện tử. Schema trông như thế này: Chọn dữ liệu từ SQL DB mỗi ngày

[Orders] Id

| SUBTOTAL | TAXAMOUNT | ShippingAmount | DateCreated

Bảng này không chỉ chứa dữ liệu cho mỗi Order. Vì vậy, nếu một ngày trôi qua mà không có bất kỳ đơn đặt hàng nào, thì không có dữ liệu bán hàng nào cho ngày đó.

Tôi muốn chọn tổng phụ mỗi ngày trong 30 ngày qua, kể cả những ngày không có doanh thu.

Kết quả sẽ trông giống như sau:

Ngày | SalesSum
2009-08-01 | 15235
2009-08-02 | 0
2009-08-03 | 340
2009-08-04 | 0
...

Việc làm này, chỉ mang lại cho tôi dữ liệu cho những ngày với đơn đặt hàng:

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

Bạn có thể tạo một bảng gọi là Ngày, và chọn từ bảng và tham gia vào bảng Orders. Nhưng tôi thực sự muốn tránh điều đó, bởi vì nó không hoạt động đủ tốt khi giao dịch với các múi giờ và sự vật khác nhau ...

Xin đừng cười. SQL không phải là loại điều của tôi ... :)

+0

bạn đang sử dụng gì? Câu trả lời có thể thay đổi nếu bạn đang sử dụng MySQL, hoặc SQL Server, hoặc cái gì khác ... – AnonJr

+0

Tôi đang sử dụng MS SQL Server – MartinHN

Trả lời

2

Tạo một chức năng mà có thể tạo ra một bảng cập nhật như sau:
(bị đánh cắp từ 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 

Sau đó, tham gia vào bảng đó

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

Với một số liệu được chọn sửa đổi một chút, nó hoạt động: SELECT dates.date, ISNULL (SUM (ordersubtotal), 0) như Sales FROM [ dbo]. [DateTable] ('2009-08-01', '2009-08-31', 'day') dateLEFT JOIN đơn đặt hàng trên CONVERT (VARCHAR (10), Orders.datecreated, 111) = date.dategroup theo ngày .date – MartinHN

+0

Tôi đã cập nhật truy vấn thứ hai. Tôi đã có trường ngày sai trong select/group by, do đó giới hạn nó chỉ với ngày có bán hàng. Tôi đã thử nghiệm phiên bản này, và tôi nghĩ nó mang lại những gì bạn muốn. Nó có NULL thay vì 0 cho những ngày không có doanh thu, nhưng bạn có thể dễ dàng sử dụng hàm COALESCE để xóa chúng. – JamesMLV

+0

Tôi không thể làm việc này để làm pho mát. Ai đó có thể cho tôi biết câu trả lời chính xác không? – 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 - Tôi đã bỏ lỡ phần '30 ngày qua'. Các bit ở trên, trong khi không phải là sạch sẽ, IMHO, như bảng ngày, nên làm việc. Một biến thể khác là sử dụng vòng lặp while để điền vào một bảng tạm thời chỉ với 30 ngày qua và thực hiện một phép nối ngoài bên trái với kết quả của truy vấn ban đầu của tôi.

+0

Chỉ cần thêm mệnh đề where trong 30 ngày qua – jdelator

+4

Điều này sẽ không bao gồm bất kỳ ngày nào mà don ' t có bất kỳ bán hàng trong họ (như ban đầu yêu cầu) – scwagner

+0

Nếu chỉ là dễ dàng :) Tôi cần mỗi ngày, trong 30 ngày qua. – MartinHN

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

kể cả những ngày không có doanh thu.

Đó là phần khó khăn. Tôi không nghĩ câu trả lời đầu tiên sẽ giúp bạn với điều đó. Tôi đã làm một cái gì đó tương tự như thế này với một bảng ngày riêng biệt.

Bạn có thể tìm hướng dẫn về cách làm như vậy ở đây:

Date Table

+0

Thực ra, tôi đã giả định rằng những ngày không có doanh thu sẽ không nằm trong bảng. Nếu không, hãy bỏ qua câu trả lời của tôi. – DavidStein

+0

Nó không phải là. Bảng chỉ chứa dữ liệu cho mỗi Đơn đặt hàng. Vì vậy, nếu một ngày trôi qua mà không có đơn đặt hàng, không có dữ liệu bán hàng nào cho ngày cụ thể đó. – MartinHN

+1

Sau đó, tôi sẽ tạo ra một bảng ngày với tất cả các ngày và sau đó làm một trái tham gia vào một truy vấn mà sẽ tóm tắt doanh số bán hàng mỗi ngày. Bạn cũng nên nhớ sử dụng một câu lệnh kết hợp để trả về số không thay vì null cho các ngày không có doanh thu. Tôi đã phải làm điều này trong nhiều tình huống khác nhau và bảng ngày bên ngoài là con đường để đi. – DavidStein

0

Tôi thực sự đã làm điều này ngày hôm nay. Chúng tôi cũng có một ứng dụng thương mại điện tử. Tôi không muốn điền vào cơ sở dữ liệu của chúng tôi với những ngày "vô dụng". Tôi chỉ làm nhóm theo và tạo tất cả các ngày cho N ngày cuối cùng trong Java, và ngang hàng chúng với các kết quả ngày/bán hàng từ cơ sở dữ liệu.

0

Điều này cuối cùng sẽ kết thúc ở đâu? Tôi yêu cầu chỉ vì nó có thể được dễ dàng hơn để điền vào những ngày trống rỗng với bất cứ chương trình sẽ đối phó với các dữ liệu thay vì cố gắng để làm cho nó được thực hiện trong SQL.

SQL là một ngôn ngữ tuyệt vời, và nó có khả năng rất nhiều thứ, nhưng đôi khi bạn chỉ tốt hơn làm việc các điểm tốt hơn của dữ liệu trong chương trình thay thế.

1

Tôi có bảng bảng nhật ký với LogID một chỉ mục mà tôi không bao giờ xóa bất kỳ bản ghi nào. nó có chỉ số từ 1 đến ~ 10000000. Sử dụng bảng này tôi có thể viết

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

(sửa đổi một chút - Tôi nhấn enter quá sớm)

tôi bắt đầu chọc lúc này, và khi nó chạm một số khái niệm SQL khá khó khăn nó nhanh chóng phát triển thành như sau quái vật. Nếu khả thi, bạn có thể thích ứng tốt hơn với giải pháp của THEn; hoặc, giống như nhiều người khác khuyên, sử dụng mã ứng dụng để điền vào các khoảng trống có thể thích hợp hơn.

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

Bước 1 là tạo bảng tạm thời chứa 30 ngày bạn quan tâm. Sự khải huyền trừu tượng đó là về cách nhanh nhất được biết để xây dựng một bảng các số nguyên liên tiếp; thêm một vài truy vấn con khác và bạn có thể điền hàng triệu hoặc nhiều hơn chỉ trong vài giây. Tôi lấy 30 đầu tiên, và sử dụng dateadd và ngày/giờ hiện tại để chuyển đổi chúng thành ngày tháng. Nếu bạn đã có một bảng "cố định" có 1-30, bạn có thể sử dụng nó và bỏ qua toàn bộ CTE (bằng cách thay thế bảng "Tally" bằng bảng của bạn).

Hàm hai ngày bên ngoài gọi loại bỏ phần thời gian của chuỗi được tạo.

(Lưu ý rằng tôi giả định rằng ngày đặt hàng của bạn cũng không có phần thời gian - nếu bạn đã có một vấn đề phổ biến để giải quyết.)

Đối với mục đích thử nghiệm tôi đã xây dựng #orders bảng, và điều này được bạn phần còn lại:

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

Điều này được dựa trên SQL Server 2005, trong đó các biểu thức bảng chung (mệnh đề "WITH" xấu xí) đã được giới thiệu. Có nhiều cách khác để có được những kết quả này, nhưng CTE là nhanh nhất cho việc xây dựng bảng đặc biệt. –

0

Tôi đã tạo DateTable chức năng như JamesMLV chỉ ra cho tôi.

Và sau đó SQL trông như thế này:

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 
Các vấn đề liên quan