0

这是选择:

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

我认为选择子句。它太长了,例如是否可以考虑DATEDIFF(MINUTE, o.StartDate, o.EndDate)变量或其他东西。

4

2 回答 2

0

几件事。

尽可能在执行 JOIN 之前划分查询并在各个表上应用过滤器。更新局部变量的数据类型以匹配表中列的数据类型。在 WHERE 条件下使用左侧列上的函数不好,索引不会用于此类查询。在您的情况下,该声明是:

转换(日期,o.StartDate)> = @StartDate

转换(日期,o.StartDate)<= @EndDate

而是将 @StartDate 更新为 Datetime 或任何列类型 o.StartDate 。我看到您只需要比较日期而不是时间部分,因此在使用零时间部分进行查询之前更新/添加传入的本地参数值。与@EndDate 相同。

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

如果集群然后 (Overtimes.StartDate , Overtimes.EmployeeId)

If Covering Non-Clustered Then (Overtimes.StartDate) Include (EmployeeId)

对于表员工和组,请确保您具有相似的索引。

Clustered/NonClustered --> (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
于 2013-10-25T15:02:22.040 回答
0

正如 Joe W 在评论中提到的那样,您可以将 common datediff 移动到一个通用表达式以稍微简化事情,例如 (the untested);

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
于 2013-10-25T13:44:49.053 回答