【问题标题】:Improve SQL Server query改进 SQL Server 查询
【发布时间】:2014-11-24 15:46:44
【问题描述】:

我必须改进这个查询,效果很好。

DECLARE     @timTimeout int, 
        @iniDate varchar(20), 
        @endDate varchar(20)            
SET         @iniDate = '2014-07-20 00:00:00'              
SET         @endDate = '2014-11-24 23:59:59'           
SET         @timTimeout = 4000                       

SET ANSI_WARNINGS OFF

SELECT 
            'Approved (0200)' = ISNULL(SUM(CASE CodMsgIncome WHEN '0200' THEN 1 END), 0),
            'Approved Off (0220)' = ISNULL(SUM(CASE CodMsgIncome WHEN '0220' THEN 1 END), 0),
            'Cancel (0400)' = ISNULL(SUM(CASE CodMsgIncome WHEN '0400' THEN 1 END), 0),
            'Regret (0420)' = ISNULL(SUM(CASE CodMsgIncome WHEN '0420' THEN 1 END), 0),
            'TOTAL' = COUNT(*),
            'Time-outs' = ISNULL(SUM(CASE WHEN DATEDIFF(ms, DateMsgIncome, DateMsgSent) > @timTimeout THEN 1 END), 0),
            'Disponibility (%)' = (1 - CAST(ISNULL(SUM(CASE WHEN DATEDIFF(ms, DateMsgIncome, DateMsgSent) > @timTimeout THEN 1 END), 0) as money) / COUNT(*)) * 100
FROM Message (NOLOCK)
    WHERE DateMsgIncome BETWEEN @iniDate AND @endDate
            AND CodMsgIncome IN ('0200', '0220', '0400', '0420', '0800', '0900', '9080', '9085') 
            AND DescMsgIncome <> '0220'

现在,我必须准备一份包含按月组织的总数据的报告。

disered 的输出看起来像这样:

      Approved (0200) | Approved Off (0220) | Cancel | Total | Time-outs | Disponibility (%)
July | 35                   15                   12      62       0            100.00
.
.
.

编辑: 我的查询中只有一张表。

  Table Message:
DateMsgIncome date,
DateMsgSent date,
CodMsgIncome varchar(4),
DescMsgIncome varchar(4),
CodMsgAnswer int.

欢迎提出任何建议。 提前致谢。

【问题讨论】:

  • 您没有收到任何错误,是吗?您想以何种方式改进该查询?速度方面,美学方面,还是什么?
  • 好吧,我不知道如何按月对数据进行分组。这是我想要的改进。
  • 这是模糊的,因为你没有描述你有什么表结构。当我们甚至不知道从哪个列中选择那个月份时,我们怎么知道如何按月份分组呢? (例如 DateMsgIncome、DateMsgSent 似乎都是 DateTime 列)
  • 除此之外,向查询添加分组并不是我所说的改进,而更像是更改请求;)
  • 所以添加一个 GROUP BY 你的两个日期列之一的月份。我们不知道是哪一个。

标签: sql sql-server


【解决方案1】:

我通过代码格式化程序运行了您的查询以帮助清理它。我还更改了变量声明,因为您似乎不明白我在说什么。作为记录,您编码的方式可能在一天的最后几毫秒内错过了一些行。

我更改了 DATEDIFF 函数以使用拼写出来的日期部分名称,因为使用错误的缩写太容易弄错了。我还简化了最后一列的计算。如果您将 1 - 更改为 1.0 -,则不需要转换为金钱。您应该避免对对象名称使用保留字,并避免在列名中使用空格。让前端做这种漂亮的格式化。

在使用表格提示时,我还添加了需要的 WITH 关键字。 (我建议在使用之前了解 NOLOCK 的真正含义)。

DECLARE @timTimeout int
    , @iniDate date
    , @endDate date

SET @iniDate = '2014-07-20'              
SET @endDate = '2014-11-25'           
SET @timTimeout = 4000                       

SELECT MONTH(DateMsgIncome) as MyMonthColumn
    , 'Approved (0200)' = ISNULL(SUM(CASE CodMsgIncome WHEN '0200' THEN 1 END), 0)
    , 'Approved Off (0220)' = ISNULL(SUM(CASE CodMsgIncome WHEN '0220' THEN 1 END), 0)
    , 'Cancel (0400)' = ISNULL(SUM(CASE CodMsgIncome WHEN '0400' THEN 1 END), 0)
    , 'Regret (0420)' = ISNULL(SUM(CASE CodMsgIncome WHEN '0420' THEN 1 END), 0)
    , 'TOTAL' = COUNT(*)
    , 'Time-outs' = ISNULL(SUM(CASE WHEN DATEDIFF(MILLISECOND, DateMsgIncome, DateMsgSent) > @timTimeout THEN 1 END), 0)
    , 'Disponibility (%)' = (1.0 - ISNULL(SUM(CASE WHEN DATEDIFF(MILLISECOND, DateMsgIncome, DateMsgSent) > @timTimeout THEN 1 END), 0) / COUNT(*)) * 100
FROM [Message] WITH (NOLOCK) --Ack!!! I wouldn't let this fly on my system due to inconsistencies with this hint unless accuracy is not important (like 

WHERE DateMsgIncome >= @iniDate 
    AND DateMsgIncome < @endDate
    AND CodMsgIncome IN 
    (
        '0200'
        , '0220'
        , '0400'
        , '0420'
        , '0800'
        , '0900'
        , '9080'
        , '9085'
    ) 
    AND DescMsgIncome <> '0220'
GROUP BY MONTH(DateMsgIncome)

【讨论】:

  • 它是一个非常需要的表,我必须防止它被锁定。这就是上面有nolock 的原因。我会测试你的答案。感谢您的帮助。
  • 我知道你不想锁定它。我只是经常看到这个提示,用户不知道它在做什么。它可以并且将会丢失和/或重复行。 blogs.msdn.com/b/davidlean/archive/2009/04/06/…
  • 它按我的需要工作。我只在where 子句之后调整group by。感谢您的帮助和耐心。我不擅长 SQL,但现在,我是这里唯一一个做这个报告的人。再次感谢您。
  • 天哪……我比这更清楚。我将相应地编辑我的答案。 :) 很高兴这对你有用。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2021-08-16
  • 2021-09-02
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多