2015-04-01 52 views
1

我开发了一些SQL来生成我们的本地故障单数据库表(SQL Server 2008)的统计信息。从我的代码中可以看到,我想从TICKETS中选择,加入组以获取组名称,按组代码以及年/月分组。SQL生成多个计数列

我想创建总计(计数)多少张门票是打开,关闭,在sla(过期日期)之外关闭的,最终是SLA%。

此代码有效,但我不满意编码所有嵌套(选择计数);这似乎不是一个很好的策略与多次重新扫描。

是否有更好的设计来从桌面上的单个选择生成多个“计数”列......或者这是标准方法吗?

select g.group_name as [Group], 
     year(tm.date_open) as Year, 
     month(tm.date_open) as Month, 
     COUNT(*) as [Tickets Opened], 

     (select COUNT(*) 
     from TICKETS tm2 
     where tm2.group_code = tm.group_code 
     and year(tm2.COMPLETION_DATE) = year(tm.date_open) 
     and month(tm2.COMPLETION_DATE) = month(tm.date_open) 
     ) as [Tickets Closed], 

     (select COUNT(*) 
     from TICKETS tm2 
     where tm2.group_code = tm.group_code 
     and year(tm2.COMPLETION_DATE) = year(tm.date_open) 
     and month(tm2.COMPLETION_DATE) = month(tm.date_open) 
     and tm2.[COMPLETION_DATE] <= tm2.[DUE_DATE:] 
     ) as [Closed Within SLA], 

     (select COUNT(*) 
     from TICKETS tm2 
     where tm2.group_code = tm.group_code 
     and year(tm2.COMPLETION_DATE) = year(tm.date_open) 
     and month(tm2.COMPLETION_DATE) = month(tm.date_open) 
     and tm2.[COMPLETION_DATE] > tm2.[DUE_DATE:] 
     ) as [Closed Outside SLA] --service level agreement 


from TICKETS tm 
left join GROUPS g on g.group_code = tm.group_code 
where g.group_code in ('techs', 'reps', 'phone') 

and year(tm.date_open) = 2015 
--and month(tm.date_open) = 3 -- specific month 

group by tm.group_code, g.group_name, year(tm.date_open), month(tm.date_open) 

order by g.group_name, year(tm.date_open), month(tm.date_open) 

,我也要去想添加SLA%列将被([关闭在SLA]/[关闭门票])* 100。但是,当我看到它从我目前的设计,我会为另一列添加冗余嵌套SELECTS,例如...

(
    cast((select COUNT(*) 
    from TICKETS tm2 
    where tm2.group_code = tm.group_code 
    and year(tm2.COMPLETION_DATE) = year(tm.date_open) 
    and month(tm2.COMPLETION_DATE) = month(tm.date_open) 
    and tm2.[COMPLETION_DATE] <= tm2.[DUE_DATE:] 
    ) as decimal)/
    (select COUNT(*) 
    from TICKETS tm2 
    where tm2.group_code = tm.group_code 
    and year(tm2.COMPLETION_DATE) = year(tm.date_open) 
    and month(tm2.COMPLETION_DATE) = month(tm.date_open) 
    ) 
) * 100 as [SLA%] 

回答

3

是的,你可以比一堆子查询做得更好。在单个聚合查询中,通过计算满足条件时评估为1的各种表达式,可以获得满足不同条件的单独行数,否则为零。或者,您可以使用COUNT()表达式计算出您想计算的那些行的非NULL。例如,它看起来像这样可能接近你之后:

SELECT 
    g.group_name AS [Group], 
    year(tm.date_open) as Year, 
    month(tm.date_open) as Month, 
    COUNT(*) AS [Tickets Opened], 
    COUNT(tm.completion_date) AS [Tickets Closed], 
    SUM(CASE WHEN tm.completion_date <= [DUE_DATE:] THEN 1 ELSE 0 END) 
    AS [Closed Within SLA], 
    SUM(CASE WHEN tm.completion_date > [DUE_DATE:] THEN 1 ELSE 0 END) 
    AS [Closed Outside SLA], --service level agreement 
    CAST(SUM(CASE WHEN tm.completion_date <= [DUE_DATE:] THEN 1 ELSE 0 END) 
    AS decimal)/COUNT(tm.completion_date)) AS [SLA%], 
FROM 
    tickets tm 
    LEFT JOIN GROUPS g 
    ON g.group_code = tm.group_code 
WHERE 
    g.group_code in ('techs', 'reps', 'phone') 
    and year(tm.date_open) = 2015 
    -- and month(tm.date_open) = 3 -- specific month 
GROUP BY 
    tm.group_code, 
    g.group_name, 
    year(tm.date_open), 
    month(tm.date_open) 
ORDER BY 
    g.group_name, 
    year(tm.date_open), 
    month(tm.date_open) 
+0

这很好,约翰。我按照你的例子修改了我的查询,效果很好。这个策略对我来说是好学的。感谢那。另外要注意的是,速度的增加是巨大的。我的嵌套select语句运行了大约30秒。在修改你的方法后,我认为有什么不对,因为当我运行它时,响应几乎是立即的,不到一秒钟!谢谢。 – Riccarr 2015-04-01 20:04:50

+0

我不确定Stackoverflow上的协议...所以虽然答案是一个很好的例子,如何重写我的问题,并且我认为它是完美的,经过仔细分析,结果实际上对我的情况并不准确。问题是在我的情况下,一张票可能会在一个月结束并在下个月关闭。我的原始设计将准确地包括[闭门票]计数中的那些,而在约翰的方法中,由于开放和结束的月份不同,所以错过了这些计数。我不知道如何解释这是这种设计? – Riccarr 2015-04-01 23:15:39

+0

@Riccarr,如果我已经充分回答了你提出的问题*,那么你应该考虑我的答案是接受的候选人。当然,你可以像你一样在评论中进一步讨论答案。关于您观察到的行为差异,您可以使用我提供的技术来改变票据被视为已关闭的条件。然而,我观察到,我认为你有它倒退:我提出的查询将计数每个组中具有非'NULL'完成日期“关闭”的所有*票据;原来只计算在同一个月内完成的。 – 2015-04-02 15:54:58