我应该在这个存储过程中使用WHILE循环还是有另一种方法来获得相同的结果?

时间:2014-03-05 14:08:01

标签: sql sql-server loops stored-procedures

我正在制作一个存储过程来检查假日预订应用程序的用户输入日期的天数,显然如果关闭的用户数量大于一次允许关闭的用户数量那么它将抛出一个错误,这个循环工作(我认为),但我已经在其他地方读过你应该尽量避免SQL中的循环所以我正在寻找一些帮助!继承我的存储过程代码:

CREATE PROCEDURE spBusinessRuleValidation
(
@StartDate DATE,
@EndDate DATE,
@EmployeeID INT
)


/****
Name: spdolater
description: checks business rules
****/

AS
    BEGIN
        DECLARE @JobRoleID INT
        DECLARE @MaxJobTypeAllowedOff INT       
        DECLARE @MaxEmployeesAllowedOff INT
        DECLARE @DateCount INT
        DECLARE @SameJobRoleOff INT
        DECLARE @DateCheck DATE

        SET @JobRoleID = (SELECT JobRoleID FROM Employees WHERE @EmployeeID = Employees.ID)
        SET @MaxJobTypeAllowedOff = (SELECT MaxEmployeesAllowedOff FROM JobRole WHERE @JobRoleID = JobRole.ID)
        SET @MaxEmployeesAllowedOff = 20
        SET @DateCheck = @StartDate
        SET @EndDate = DATEADD(DAY, 1, @EndDate)

        WHILE (@DateCheck <> @EndDate)
        BEGIN
            SET @DateCount = (SELECT COUNT (@DateCheck) FROM Holidays)
            IF @DateCount > @MaxEmployeesAllowedOff
            BEGIN
                /*error*/
            END


            SET @SameJobRoleOff = (SELECT COUNT (*) JobRoleID
            FROM Employees
            RIGHT JOIN Holidays
            ON Employees.ID = Holidays.EmployeeID
            WHERE @EmployeeID = Employees.ID
            AND @DateCheck = Holidays.StartDate)

            IF @SameJobRoleOff > @MaxJobTypeAllowedOff
            BEGIN
                /*error*/
            END

            SET @DateCheck = DATEADD(DAY, 1, @DateCheck)
        END


    END

如果您希望我更多地解释代码和逻辑,请询问。

inb4 OP喜欢变量:)

1 个答案:

答案 0 :(得分:0)

你是对的,你永远不应该在SQL中使用循环。 SQL使用集合,您必须根据集合来考虑您的问题。

很明显,您在上面列出的代码无法使用且尚未经过测试。它可以用这种方式编写,但速度很慢。

让我们从集合的角度思考解决问题并迭代地解决问题。这样,如果我不了解您的模型或您的业务规则,您将很容易纠正。

通常,您要检查开始日期和结束日期之间的所有日期,以查看是否有任何未通过标准检查的日期。

首先,找到所有这些日期(作为一组),如下所示:

SELECT *
FROM Holidays AS H
WHERE H.Date BETWEEN @startdate and @enddate

查找每天的计数

SELECT count(*) as [takenbydate], H.Date
FROM Holidays AS H
WHERE H.Date BETWEEN @startdate and @enddate
GROUP BY H.Date

SELECT Count() OVER (PARTITION BY H.Date) AS C, *
FROM Holidays AS H
WHERE H.Date BETWEEN @startdate and @enddate

现在我们要检查允许的最大值。为此,我们加入到最大允许表,我们也加入到employee表中以获取作业角色信息,据我所知,在max allowed table中没有日期。如果有,那么在join语句中需要另一个AND子句。

SELECT Count() OVER (PARTITION BY H.Date) AS C, R.MaxEmployeesAllowedOff, H.*
FROM Holidays AS H
JOIN Employees AS E ON E.ID = @EmployeeID 
JOIN JobRole AS R ON R.ID = E.JobRoleID
WHERE H.Date BETWEEN @startdate and @enddate

现在我们检查规则

SELECT * 
FROM
(
  SELECT Count() OVER (PARTITION BY H.Date) AS C, R.MaxEmployeesAllowedOff, H.*
  FROM Holidays AS H
  JOIN Employees AS E ON E.ID = @EmployeeID 
  JOIN JobRole AS R ON R.ID = E.JobRoleID
  WHERE H.Date BETWEEN @startdate and @enddate
) sub
WHERE MaxEmployeesAllowedOff < C OR C > 20

如果此查询返回任何结果,则表示您遇到问题。

  

注意,我添加了Holiday的所有字段以供参考,但是最后一个   查询不需要这些列。最终查询的任何结果   会显示应该抛出一个错误,所需要的只是   你提出的规则的前两列。