【问题标题】:Updating table based on date field without using loops with sql基于日期字段更新表而不使用 sql 循环
【发布时间】:2016-05-28 02:51:24
【问题描述】:

我创建了以下脚本来更新 Microsoft SQL Server 中的计划表。主键字段是日期时间,是日历上的各个日期。员工计划连续工作 7 天,从每周一到周日到年底,我需要在 2 名员工之间轮换 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;

【问题讨论】:

  • 您可以很容易地为此使用数字或计数。我还敦促您对日期字符串使用 ANSI 格式。 'YYYYMMDD' 如果日期格式或本地化与您的不同,您拥有日期字符串的方式将失败。这是到计数表的一个很好的链接。 sqlservercentral.com/articles/T-SQL/62867
  • 您因寻找一种不使用循环来完成它的方法而获得了丰厚的+1! (我现在没有时间编写这个脚本,但我稍后会回来(但可能它已经回答了......)
  • 我在这里有点困惑。您的第二个循环正在覆盖您在第一个循环中更新的数据。
  • 你只需要为两个员工做这个吗?
  • 我只需要 2 名员工这样做是的。因此,从 2016 年 3 月 7 日星期一到 2016 年 3 月 13 日星期日开始,我需要安排吉姆。从 2016 年 3 月 8 日星期一开始到 2016 年 3 月 14 日星期日安排安迪,在年底之前重复这种模式。

标签: sql sql-server loops datetime


【解决方案1】:

最佳方法是填充持久化的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

【讨论】:

    【解决方案2】:

    您可以使用 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
    

    【讨论】:

      猜你喜欢
      • 2017-01-21
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2014-02-19
      • 1970-01-01
      • 2014-09-17
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多