2

我必须创建一个报告,其中 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)
4

2 回答 2

2

看起来不错,但我建议进行一项性能改进:

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

这会将聚合限制为您需要的行。. . 除非您希望列出的所有内容都包含空数据。

我倾向于添加else 0case语句中,所以出现的是 0 而不是 NULL。

于 2012-12-12T21:34:55.063 回答
1

@PaulStock,很高兴这样做。

这种技术发挥了 RDMS 的优势,即数据检索和集合操作 - 将迭代留给其他更优化的编程语言,如 C#。

首先,您需要一个IndexTable,我将我的保存在主数据库中,但如果您没有对此的写访问权,请务必将其保存在您的数据库中。

它看起来像这样:

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这里使用了一个,所以如果在给定的日期没有交易,那么我们没有行,但是 aLEFT JOIN会将这些空日期作为总计(如果你想得到 0,请NULL使用语句。ISNULL

使用标准化数据,您可以PIVOT根据需要获得所需的输出。

于 2012-12-20T04:07:01.627 回答