2012-12-12 27 views
2

我必須創建一個報表,其中AccountSegment以行和2周的日期範圍作爲列標題。列值將是具有關聯的段/日期範圍的表中的記錄數的計數。是否有更有效的方式按日期分組在SQL Server 2008中

因此所需的輸出看起來是這樣的:

AcctSeg 4/9/12-4/20/12 4/23/12-5/4/12 5/7/12-5/18/12 
Segment1  100    200    300 
Segment2  110    220    330 
Segment3  120    230    340 

下面的查詢我想要做什麼,但只是看起來如此低效和醜陋。我想知道是否有更好的方式來完成同樣的事情:

SELECT 
    AccountSegment = S.Segment_Name, 
    '4/9/2012 - 4/20/2012' = SUM(CASE WHEN date_start BETWEEN '2012-04-09' AND '2012-04-20' THEN 1 END), 
    '4/23/2012 - 5/4/2012' = SUM(CASE WHEN date_start BETWEEN '2012-04-23' AND '2012-05-04' THEN 1 END), 
    '5/7/2012 - 5/18/2012' = SUM(CASE WHEN date_start BETWEEN '2012-05-07' AND '2012-05-18' THEN 1 END), 
    '5/21/2012 - 6/1/2012' = SUM(CASE WHEN date_start BETWEEN '2012-05-21' AND '2012-06-01' THEN 1 END), 
    '6/4/2012 - 6/15/2012' = SUM(CASE WHEN date_start BETWEEN '2012-06-04' AND '2012-06-15' THEN 1 END), 
    '6/18/2012 - 6/29/2012' = SUM(CASE WHEN date_start BETWEEN '2012-06-18' AND '2012-06-29' THEN 1 END), 
    '7/2/2012 - 7/13/2012' = SUM(CASE WHEN date_start BETWEEN '2012-07-02' AND '2012-07-13' THEN 1 END), 
    '7/16/2012 - 7/27/2012' = SUM(CASE WHEN date_start BETWEEN '2012-07-16' AND '2012-07-27' THEN 1 END), 
    '7/30/2012 - 8/10/2012' = SUM(CASE WHEN date_start BETWEEN '2012-07-30' AND '2012-08-10' THEN 1 END) 
FROM 
    dbo.calls C 
    JOIN dbo.accounts a ON C.parent_id = a.id 
    JOIN dbo.accounts_cstm a2 ON a2.id_c = A.id 
    JOIN dbo.Segmentation S ON a2.[2012_segmentation_c] = S.Segment_Num 
WHERE 
    c.deleted = 0 
GROUP BY 
    S.Segment_Name 
ORDER BY 
    MIN(S.Sort_Order) 
+0

醜陋的可能,但效率不高的歸一化數據。 - 可能不是我見過的數據倉庫/報告類型系統的許多這樣的質疑。 –

+0

有一個更好的方法,但它可能不適合你。它需要間隔是相同的大小和順序,你rs似乎不是。讓我知道,如果這是你會感興趣的。 –

+0

@DaleM我很好奇你的建議方法是什麼。謹慎闡述? – PaulStock

回答

2

它看起來不錯,但我會建議一個性能改進:

where c.deleted = 0 and 
     date_start between '2012-04-09' AND '2012-08-10' 

這將匯聚只限制行你需要。 。 。除非您希望列出的所有數據都是空的。

我傾向於將else 0添加到case語句,所以0出現而不是NULL。

1

@PaulStock,很高興能這樣做。

這種技術發揮了RDMS的優勢,即數據檢索和集合處理 - 留給其他編程語言更好,像C#一樣對其進行優化。

首先你需要一個IndexTable,我把它保存在master數據庫中,但是如果你沒有寫入權限的話,一定要把它保存在你的db中。

它看起來像這樣:

Id 
0 
1 
2 
... 
n 

哪裏n是所有的場景數量足夠多,10爲好,1,000,000更好,10,000,000甚至更好。列id當然是集羣索引。

我不打算直接將它與您的查詢相關,因爲我並不真正瞭解它,而且我也懶得去解決它。

相反,我會把它涉及到這個表稱爲Transactions,在這裏我們要捲起來,發生在每一天的所有交易(或每週或每月等):

Date      Amount 
2012-18-12 04:58:56.453  10 
2012-18-12 06:34:21.456  100 
etc 

下面的查詢將推出向上按天的數據

SELECT i.Id, SUM(t.Amount) AS DailyTotal 
FROM IndexTable i 
     INNER JOIN 
     Transactions t ON i.Id=DATEDIFF(DAY, 0, t.Date) 
GROUP BY i.Id 

DATEDIFF函數返回2個日期之間的日期部分的數量,在這種情況下的天數0 1900-01-01之間:(在SQL Server的DateTime = 0)00.000:00和交易的日期(順便說一句自那時以來已經41,261天了 - 看看爲什麼我們需要一張大桌子)

當天所有的交易都會有相同的號碼。更改爲周或月或秒(非常大的數字)與更改日期部分一樣簡單。

只要比您感興趣的數據早一點,您就可以放入比此更晚的開始日期,但它對性能毫無影響。

我已經使用了INNER JOIN這裏,所以,如果有在某一天沒有交易那麼我們就沒有行,但一個LEFT JOIN會給這些空日期與NULL,如果你想獲得0總(使用ISNULL聲明。

隨着然後你可以PIVOT根據需要獲取輸出你正在尋找

相關問題