有关软件/数据库设计的建议,以避免在更新数据库时使用游标

时间:2010-05-20 10:04:57

标签: sql-server cursor

我有一个数据库,可以记录员工参加课程以及下次参加课程的时间(课程往往是年度课程)。

例如,以下员工于2010年1月1日参加了“1”课程,并且该课程是每年一次,将于2011年1月1日参加。截至今天是2010年5月20日,课程状态显示为'完成'即他们已经完成了课程,并且在明年之前不需要再做一次:

EmployeeID    CourseID    AttendanceDate    DueDate     Status
123456        1           01/01/2010        01/01/2011  Complete

DueDate而言,我在更新员工记录时在SQL中对此进行计算,例如DueDate = AttendanceDate + CourseFrequency(我从一个单独的表中提取课程频率)。

在我的基于网络的应用程序(asp.net mvc)中,我为所有员工提取这些数据,并以类似网格的格式显示,供人力资源经理审核。这使人力资源部门能够确定需要参加课程的人员。

我遇到的问题如下。

以上面的例子为例,假设今天是2011年1月2日。在这种情况下,员工123456现在已经过期了,我想将Status设置为Incomplete,以便HR经理可以看到他们需要采取行动,即让员工参加课程。

我可以在数据库中构建一个触发器,以便在一夜之间运行,根据当前日期更新所有员工的Status字段。根据我的阅读,我需要使用游标来遍历每一行以修改状态,这被认为是不好的做法/效率低下或至少要避免的事情,如果你可以???

或者,在我从数据库中撤回数据之后,在我在屏幕上显示数据之前,我可以在我的C#代码中计算Status。这个问题是数据库中的Status不一定与屏幕上显示的内容相匹配,这对我来说是错误的。

有没有人对这种问题的最佳实践方法有任何建议?

这有帮助,如果我使用了游标,我怀疑在任何给定时间我都会循环超过1000条记录。也许这个数量很小,使用游标是可以的吗?

3 个答案:

答案 0 :(得分:5)

除非我遗漏了你的解释,否则根本不需要游标:

UPDATE
    dbo.YourTable
SET
    Status = ‘Incomplete’
WHERE
    DueDate < GETDATE()

最好不要为这些记录维护DueDate或Status。我希望看到Employee,Course,EmployeeCourse和EmployeeCourseAttendance表,您可以使用以下表格:

-- Employees that haven't attended a course 
-- within dbo.Course.Frequency of current date
SELECT
    ec.EmployeeID
    , ec.CourseID
    , eca.LastAttendanceDate
    , DATEADD(day, c.Frequency, eca.LastAttendanceDate) AS DueDate
FROM
    dbo.EmployeeCourse ec
INNER JOIN
    dbo.Course c
LEFT OUTER JOIN
    ebo.EmployeeCourseAttendance eca
ON  eca.EmployeeID = ec.EmployeeId
AND eca.CourseID = ec.CourseID
WHERE
    GETDATE() > DATEADD(day, c.Frequency, eca.LastAttendanceDate)

-- Show all employees and status for each course
SELECT
    ec.EmployeeID
    , ec.CourseID
    , eca.LastAttendanceDate
    , DATEADD(day, c.Frequency, eca.LastAttendanceDate) AS DueDate
    , CASE
        WHEN eca.LastAttendanceDate IS NULL THEN 'Has not attended'
        WHEN (GETDATE() > DATEADD(day, c.Frequency, eca.LastAttendanceDate) THEN 'Incomplete'
        WHEN (GETDATE() < DATEADD(day, c.Frequency, eca.LastAttendanceDate) THEN 'Complete'
      END AS Status
FROM
    dbo.EmployeeCourse ec
INNER JOIN
    dbo.Course c
LEFT OUTER JOIN
    ebo.EmployeeCourseAttendance eca
ON  eca.EmployeeID = ec.EmployeeId
AND eca.CourseID = ec.CourseID

答案 1 :(得分:1)

您还可以使用计算列表达式。这样您就不必更新STATUS列/使其与日期保持同步

create table coureses
(
employeeid int not null,
courseid int not null,
attendancedate datetime null,
duedate datetime null,
[status] as case
    when duedate is null and attendancedate is null then 'n/a'
    when datediff(day,duedate, getdate()) > 0 then 'Incomplete'
    when datediff(day,attendancedate, getdate()) > 0 then 'Complete'
    else 'n/a'
    end
)

答案 2 :(得分:0)

我不会为此使用触发器,而是安排作业,可能在SQL服务器中。这里也不需要光标,当然只是:

UPDATE TABLE SET Status = 'Incomplete' WHERE DueDate < GetDate()