有没有办法以更好的方式重写这个选择命令?

时间:2013-10-25 13:26:10

标签: sql sql-server

这是选择:

SELECT e.Id AS EmployeeId, 
ISNULL(
SUM(CASE
    WHEN DATEDIFF(MINUTE, o.StartDate, o.EndDate) < 360 
        THEN DATEDIFF(MINUTE, o.StartDate, o.EndDate) 
    WHEN DATEDIFF(MINUTE, o.StartDate, o.EndDate) < 560
        THEN DATEDIFF(MINUTE, o.StartDate, o.EndDate) - 20
    ELSE
        DATEDIFF(MINUTE, o.StartDate, o.EndDate) - 45
    END), 0) AS OvertimeSum
FROM
    Overtimes o 
    RIGHT OUTER JOIN Employees e ON o.EmployeeId = e.Id
    INNER JOIN Groups g ON g.Id = e.GroupId
WHERE 
    (((CONVERT(DATE, o.StartDate) >= @StartDate) AND 
    (CONVERT(DATE, o.StartDate) <= @EndDate)) OR
    (o.StartDate IS NULL)) AND
    (g.ShiftModelId = @ShiftModelId)
GROUP BY e.Id

我认为是select子句。它太长了,例如可以将DATEDIFF(MINUTE, o.StartDate, o.EndDate)带入变量或其他东西。

2 个答案:

答案 0 :(得分:0)

正如Joe W在评论中提到的那样,你可以将常见的约会移动到一个共同的表达式,以简化一些事情,例如(未经测试的);

WITH cte AS (
  SELECT e.Id AS EmployeeId, DATEDIFF(MINUTE, o.StartDate, o.EndDate) Overtime
  FROM
    Overtimes o 
    RIGHT OUTER JOIN Employees e ON o.EmployeeId = e.Id
    INNER JOIN Groups g ON g.Id = e.GroupId
  WHERE 
    (((CONVERT(DATE, o.StartDate) >= @StartDate) AND 
      (CONVERT(DATE, o.StartDate) <= @EndDate)) OR
    (o.StartDate IS NULL)) AND
    (g.ShiftModelId = @ShiftModelId)
)
SELECT EmployeeId, ISNULL(SUM(CASE WHEN Overtime < 360 THEN Overtime 
                                   WHEN Overtime < 560 THEN Overtime - 20
                                   ELSE                     Overtime - 45
                                   END), 0) AS OvertimeSum
FROM cte
GROUP BY EmployeeId

答案 1 :(得分:0)

几件事。

在执行JOIN之前划分查询并对各个表应用过滤器。更新Local Variable的数据类型以匹配表中的Column Type数据。在WHERE条件中使用左侧列上的函数不好,并且索引不会用于此类查询。在你的情况下,该声明是:

CONVERT(DATE,o.StartDate)&gt; = @StartDate

CONVERT(DATE,o.StartDate)&lt; = @EndDate

而是将@StartDate更新为Datetime或o.StartDate的任何列类型。我发现你需要只比较日期而不是时间部分,所以在使用它进行查询之前,用零时间部分更新/添加传入的本地参数值。和@EndDate一样。

确保您在Overtimes.StartDate列上有索引。我不确定你有什么其他索引。或者您对此表有哪些其他类型的查询,但

如果CLUSTERED那么(Overtimes.StartDate,Overtimes.EmployeeId)

覆盖非群集然后(Overtimes.StartDate)包括(EmployeeId)

表员工和组确保您具有类似的索引。

群集/非群集 - &gt; (Groups.ShiftModelId,Groups.ID)和(Employees.GroupID)

然后尝试此查询

    SELECT EmployeeId,OvertimeSum
    FROM
    (
        SELECT  o.EmployeeId AS EmployeeId ,
                ISNULL(SUM(CASE WHEN DATEDIFF(MINUTE, o.StartDate, o.EndDate) < 360
                                THEN DATEDIFF(MINUTE, o.StartDate, o.EndDate)
                                WHEN DATEDIFF(MINUTE, o.StartDate, o.EndDate) < 560
                                THEN DATEDIFF(MINUTE, o.StartDate, o.EndDate) - 20
                                ELSE DATEDIFF(MINUTE, o.StartDate, o.EndDate) - 45
                           END), 0) AS OvertimeSum
        FROM    Overtimes o
        WHERE ( o.StartDate IS NULL ) OR ( o.StartDate BETWEEN @StartDate AND @EndDate )
        GROUP BY o.EmployeeId
    )q1
    RIGHT OUTER JOIN
    (
        SELECT e.ID AS EmployeeId
        FROM Employees e
        INNER JOIN Groups g ON g.Id = e.GroupId
        AND g.ShiftModelId = @ShiftModelId
    )q2
        ON q1.EmployeeId=q2.EmployeeId
相关问题