基于日期字段更新表而不使用带有sql的循环

时间:2016-02-16 17:25:46

标签: sql sql-server loops datetime

我创建了以下脚本来更新Microsoft SQL Server中的计划表。主键字段是日期时间,是日历上的各个日期。员工安排连续7天,我需要在每个星期一到星期日到年底之间的两个雇员之间轮换7天。我使用循环创建了以下脚本,并且正在寻找一种方法来完成它而不使用循环。谢谢!

DECLARE @z_start INT
DECLARE @z_date DATETIME

SET @z_date = '03/07/16'

WHILE(@z_date < '12/31/16')
BEGIN
    SET @z_start = 0

    WHILE(@z_start < 7) BEGIN
        UPDATE EmployeeOnCall
        SET employeeName = 'Jones, Jim'
        WHERE deptID = 25 AND weekDay = @z_date

        SET @z_date = DATEADD(dd, 1, @z_date)
        SET @z_start = @z_start + 1
    END

    SET @z_start = 0

    WHILE(@z_start < 7) BEGIN
        UPDATE EmployeeOnCall
        SET employeeName = 'Penton, Andy'
        WHERE deptID = 25 AND weekDay = @z_date

        SET @z_date = DATEADD(dd, 1, @z_date)
        SET @z_start = @z_start + 1
    END
END;

2 个答案:

答案 0 :(得分:0)

您可以使用DATEPART和CTE执行此操作。这是相关部分:

;with wkNum as (
    SELECT weekDay, EmployeeName, deptID, (DATEPART(wk, weekDay) / 2) % 2 as period 
    FROM EmployeeOnCall
)
UPDATE wkNum
SET employeename = CASE WHEN wkNum.period = 0 THEN 'Jones, Jim' ELSE 'Penton, Andy' END

这个想法是确定一年中的哪一周,将其除以2,然后按照您正在处理的员工数量对其进行模数化。 这是一个测试脚本:

DECLARE @test TABLE (weekDay datetime, employeename varchar(50), deptID int);

DEClARE @startdate datetime = '2016-02-16';
declare @enddate datetime = '2016-12-31';

;with 
 N0 as (SELECT 1 as n UNION ALL SELECT 1)
,N1 as (SELECT 1 as n FROM N0 t1, N0 t2)
,N2 as (SELECT 1 as n FROM N1 t1, N1 t2)
,N3 as (SELECT 1 as n FROM N2 t1, N2 t2)
,N4 as (SELECT 1 as n FROM N3 t1, N3 t2)
,N5 as (SELECT 1 as n FROM N4 t1, N4 t2)
,N6 as (SELECT 1 as n FROM N5 t1, N5 t2)
,nums as (SELECT ROW_NUMBER() OVER (ORDER BY (SELECT 1)) as num FROM N6)
INSERT @test (weekDay, deptID)
SELECT DATEADD(day,num-1,@startdate) as thedate, 25
FROM nums
WHERE num <= DATEDIFF(day,@startdate,@enddate) + 1


;with wkNum as (
SELECT weekDay, EmployeeName, deptID, (DATEPART(wk, weekDay) / 2) % 2 as period FROM @test
)
UPDATE wkNum
SET employeename = CASE WHEN wkNum.period = 0 THEN 'Jones, Jim' ELSE 'Penton, Andy' END

SELECT * FROM @test

如果你有一张员工表,可以像这样扩展:

DECLARE @emps TABLE (Name varchar(100));

INSERT @emps VALUES ('Dan'), ('Joe'), ('Asdf')

UPDATE eoc
SET employeename = emp.Name
FROM EmployeeOnCall eoc
INNER JOIN (SELECT ROW_NUMBER() OVER(ORDER BY Name) rn, Name FROM @emps) emp
ON ((DATEPART(wk, weekDay) / 2) % (SELECT COUNT(*) FROM @emps)) + 1 = emp.rn

答案 1 :(得分:0)

最佳方法是填充持久性Calendar表。填写10年开始的日期列表,将每天标记为工作日或周末日,附加您需要的任何列。并且只需加入它,按照您获得的边缘日期进行过滤。

您的案例并未说明您提到7天间隔的原因。 7天意味着每一天。假设您有@startdate@enddata个变量。让我们生成日期列表并将其与目标表连接。

declare
  @startdate  datetime = '20150612',
  @enddate    datetime = '20160122',
  @period_len int

set @period_len = datediff(dd, @startdate, @enddate)

;with cteCounter as
(
  select top (@period_len)
    ROW_NUMBER() OVER(ORDER BY c.object_id) as counter
  from sys.columns c
  cross join sys.columns cc
  order by counter
),
cteCalendar as
(
  select c.counter, dateadd(dd, c.counter-1, @startdate) as calendar_date
  from cteCalendar c
  order by calendar_date
)
UPDATE e SET
  employeeName = 'Jones, Jim'
FROM EmployeeOnCall e
inner join cteCalendar c on c.calendar_date = e.weekDay
WHERE e.deptID = 25