我必须创建一个报告,其中AccountSegment为行,2周的日期范围为列标题。列值将是表中具有相关段/日期范围的记录数的计数。
所以期望的输出看起来像这样:
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 :(得分:2)
看起来不错,但我建议改进一项性能:
where c.deleted = 0 and
date_start between '2012-04-09' AND '2012-08-10'
这会将聚合仅限制为您需要的行。 。 。除非你想要用空数据列出所有内容。
我倾向于将else 0
添加到case
语句中,因此显示0而不是NULL。
答案 1 :(得分:1)
@PaulStock,很高兴这样做。
这种技术发挥了RDMS的优势,即数据检索和集合操作 - 将其改为其他编程语言,如C#更好地优化它。
首先你需要一个IndexTable
,我把它放在master数据库中,但如果你没有写入权限,请将它保存在你的数据库中。
看起来像这样:
Id
0
1
2
...
n
n
对于所有场景来说都是足够大的数字,100,000是好的,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
函数返回两个日期之间的日期部分数,在这种情况下是1900-01-01 0:00:00.000(SQL Server中的DateTime = 0)和日期之间的天数。交易(从那时起已经有41,261天 - 看看为什么我们需要一张大桌子)
同一天的所有交易都会有相同的号码。更改为周或月或秒(非常大的数字)就像更改日期部分一样简单。
如果它比您感兴趣的数据更早,您可以在此之后输入一个更新的开始日期,但它会使性能无差异。
我在这里使用过INNER JOIN
所以如果某一天没有交易,那么我们就没有行,但LEFT JOIN
会将这些空日期作为总计NULL
给出(如果你想获得0,请使用ISNULL
语句。
使用标准化数据,您可以根据需要PIVOT
获取您要查找的输出。