2014-01-22 60 views
0

我試圖根據當月的總訂單爲每月接受的訂單生成報告。例如,我有一個表Orders像這樣:如何將篩選出的行與未按月篩選的行進行分組

Order_Id Submit_Date Order_Status 
-------- ----------- ------------ 
1   20130501  Accepted 
2   20130509  Rejected 
3   20130610  Accepted 
4   20130614  Accepted 
5   20130626  Rejected 
6   20130802  Accepted 
7   20130801  Accepted 
8   20131014  Accepted 
9   20140116  Rejected 
10   20140121  Rejected 

,並希望得到像這樣的結果:

[Month] Accepted Total 
------- -------- ----- 
2013-05 1   2 
2013-06 2   3 
2013-08 2   2 
2013-10 1   1 
2014-01 2   2 

我怎麼做呢?

+0

不,這是在數據庫通常DATATIME類型。我在這裏簡化了它以避免混淆。通常的SQL DATATIME函數將對其起作用。而這些只是我想出的話。訂單是Order_ID,日期是Submitted_Date。 – tijuthomas

+0

這並不能避免混淆。 –

+1

因此,讓我直接得到這個結論,然後向其他專家開發人員提出一個技術問題,並認爲他們可能會被'datetime'數據類型弄糊塗。只是爲了將來的通知不要這樣做。發佈您的數據,因爲它會以這種方式最有用。 – Zane

回答

2

假設你將永遠不會有一個時間分量,這應該只是罰款:

DECLARE @d TABLE([Order] INT, [Date] DATETIME, [Status] CHAR(8)); 

INSERT @d VALUES 
(1 ,'20130501','Accepted'), 
(2 ,'20130509','Rejected'), 
(3 ,'20130610','Accepted'), 
(4 ,'20130614','Accepted'), 
(5 ,'20130626','Rejected'), 
(6 ,'20130802','Accepted'), 
(7 ,'20130801','Accepted'), 
(8 ,'20131014','Accepted'), 
(9 ,'20140116','Rejected'), 
(10,'20140121','Rejected'); 

SELECT 
    [Month] = DATEADD(DAY, 1-DAY([Date]), [Date]), 
    Accepted = SUM(CASE WHEN [Status] = 'Accepted' THEN 1 ELSE 0 END), 
    COUNT(*) 
FROM @d 
GROUP BY DATEADD(DAY, 1-DAY([Date]), [Date]) 
ORDER BY [Month]; 

(如果你是SQL Server 2008或更新的,你應該使用DATE數據類型,以防止不必處理。任何錯誤的小時/分鐘)

如果你能有小時/分,有時,你也不會在2008年或更高,則:

SELECT 
    [Month] = DATEADD(MONTH, DATEDIFF(MONTH, 0, [Date]), 0), 
    Accepted = SUM(CASE WHEN [Status] = 'Accepted' THEN 1 ELSE 0 END), 
    COUNT(*) 
FROM @d 
GROUP BY DATEADD(MONTH, DATEDIFF(MONTH, 0, [Date]), 0) 
ORDER BY [Month]; 

我斯特龍gly建議避免使用字符串轉換進行分組的任何解決方案。日期/時間數學在SQL Server中比轉換爲字符串更有效。此外,如果您希望客戶端提供類似2013-05的東西,請使用Format(),ToString()等在客戶端上應用該字符串格式。

+0

工程很好。謝謝! – tijuthomas

0

試試:

SELECT 
    CONVERT(VARCHAR(4), YEAR(Date)) + '-' + CONVERT(VARCHAR(2), MONTH(Date)) Period, 
    SUM(CASE WHEN Status = 'Accepted' THEN 1 ELSE 0) Accepted, 
    COUNT(*) Total 

FROM Orders 
GROUP BY YEAR(Date), MONTH(Date) 
ORDER BY YEAR(Date), MONTH(Date) 
+1

根據OP的要求,這將產生類似'2013/5'而不是'2013-05'的輸出。此外,您的WHERE條款完全消除了1月份,並導致大多數其他月份的總計不準確。 –

+0

我的分心。謝謝。 – Marco

1

要獲得YYYY-DD格式,你可以使用這個

SELECT CONVERT(VARCHAR(7),[Date],20) 
    ,COUNT(CASE WHEN [status] = 'Accepted' THEN 1 
       ELSE NULL END) AS 'Accepted' 
    ,COUNT(*) AS Total 
FROM Orders 
GROUP BY CONVERT(VARCHAR(7),[Date],20) 
+0

根據OP的要求,輸出將是「2013-5」,而不是「2013-05」。也請[不要轉換爲無長度的varchar](http://sqlblog.com/blogs/aaron_bertrand/archive/2009/10/09/bad-habits-to-kick-declaring-varchar-without-length.aspx )。你的案例中有兩個'END'聲明。當我解決這個問題時,我得到「消息8120,級別16,狀態1 - 列'@ d.Date'在選擇列表中無效,因爲它不包含在聚合函數或GROUP BY子句中。我認爲這是你試圖很快得到答案的那些案例之一,你沒有對它進行測試。 –

+0

我在與您的評論同時修改我的答案。第二個查詢將生成OP – 2014-01-22 20:42:03

+0

所請求的結果您應該刪除第一個代碼段,因爲它在很多方面都是錯誤的。另外一個比較便宜的(相對)你的子字符串是'CONVERT(CHAR(7),[Date],120)''。我仍然不相信你應該使用SQL Server將它轉換爲一個字符串,然後進行分組,以獲得該演示文稿。正如我在答覆中所說的,日期數學更有效率。 –