使用聚合、连接和日期范围条件更新查询(SQL 服务器)

Update Query with Aggregate, Join and Date Range Conditions (SQL Server)

我在使用聚合更新查询时遇到了困难,无法找到这个问题的答案。我似乎尝试了每一种排列 更新,但无法使其正常工作。不过应该很简单。

两张表:

员工

╔══════════╦═══════╦═════════════════╦═══════════════╦═════════════╗
║ PersonID ║  Name ║  RangeBeginDate ║  RangeEndDate ║  HoursSched ║
╠══════════╬═══════╬═════════════════╬═══════════════╬═════════════╣
║        1 ║ Joe   ║ 3/18/2012       ║ 3/17/2013     ║ NULL        ║
║        1 ║ Joe   ║ 3/18/2013       ║ 3/17/2014     ║ NULL        ║
║        1 ║ Joe   ║ 3/18/2014       ║ 3/17/2015     ║ NULL        ║
║        2 ║ Bill  ║ 3/18/2012       ║ 3/17/2013     ║ NULL        ║
║        2 ║ Bill  ║ 3/18/2013       ║ 3/17/2014     ║ NULL        ║
║        2 ║ Bill  ║ 3/18/2014       ║ 1/10/2015     ║ NULL        ║
╚══════════╩═══════╩═════════════════╩═══════════════╩═════════════╝

日程安排

╔══════════╦═══════════╦════════════╗
║ PersonID ║ SchedDate ║ SchedHours ║
╠══════════╬═══════════╬════════════╣
║        1 ║ 3/21/2013 ║          8 ║
║        1 ║ 3/22/2013 ║          6 ║
║        1 ║ 3/23/2013 ║          9 ║
║        1 ║ 5/15/2014 ║          8 ║
║        1 ║ 6/15/2014 ║          9 ║
║        1 ║ 1/22/2015 ║          3 ║
║        2 ║ 3/29/2012 ║          8 ║
║        2 ║ 4/1/2012  ║          9 ║
║        2 ║ 5/9/2014  ║          6 ║
║        2 ║ 5/10/2014 ║          9 ║
╚══════════╩═══════════╩════════════╝

我正在尝试更新临时员工 table 以获得每个员工的总计划时间,其中计划 table 中的 SchedDate 大于或等于 RangeBeginDate 且小于或等于等于 Employees table 中的 RangeEndDate。结果应如下所示:

╔══════════╦═══════╦═════════════════╦═══════════════╦═════════════╗
║ PersonID ║  Name ║  RangeBeginDate ║  RangeEndDate ║  HoursSched ║
╠══════════╬═══════╬═════════════════╬═══════════════╬═════════════╣
║        1 ║ Joe   ║ 3/18/2012       ║ 3/17/2013     ║           0 ║
║        1 ║ Joe   ║ 3/18/2013       ║ 3/17/2014     ║          23 ║
║        1 ║ Joe   ║ 3/18/2014       ║ 3/17/2015     ║          20 ║
║        2 ║ Bill  ║ 3/18/2012       ║ 3/17/2013     ║          17 ║
║        2 ║ Bill  ║ 3/18/2013       ║ 3/17/2014     ║           0 ║
║        2 ║ Bill  ║ 3/18/2014       ║ 1/10/2015     ║          15 ║
╚══════════╩═══════╩═════════════════╩═══════════════╩═════════════╝

如果只是获取每个 PersonID 的日程总和会很容易,但要根据比较日期的 WHERE 子句获取子组的 SUM 就很困难(对我而言)。我要么得到错误,要么得到每列中的 PersonID 总计,或者只是为每个填写的 PersonID 部分填写一行。

这是给我错误的众多错误之一:

SELECT T.PersonID, Name, SubQuery.SchedSum
  FROM #Employees AS E
       INNER JOIN
    (SELECT PersonID, SUM(scheduledhours) AS SchedSum
       FROM #Schedule S
      GROUP BY PersonID)
    AS SubQuery
    SubQuery.PersonID = T.PersonID
      WHERE S.SchedDate >= E.RangeBeginDate
        AND S.SchedDate <= E.RangeEndDate

如有任何想法,我们将不胜感激。即使它是 SQL 服务器,如果可能的话,我更愿意使代码与 MySQL 兼容。谢谢! 马克

正如您描述的问题,这是 joingroup by。但是,join 需要同时考虑人物和日期:

SELECT e.PersonID, e.Name, SUM(s.SchedSum)
FROM #Employees E LEFT JOIN
     #Schedule s
     ON s.PersonId = e.PersonId and
        s.SchedDate BETWEEN e.RangeBeginDate and e.RangeEndDate
GROUP BY e.PersonID, e.Name, e.RangeBeginDate, e.RangeEndDate;

您可以很容易地将它变成 update 通过加入结果:

UPDATE e
    SET HoursSched = ssum
    FROM #Employees e JOIN
         (SELECT e.PersonID, e.RangeBeginDate, e.RangeEndDate, SUM(s.SchedSum) as ssum
          FROM #Employees E LEFT JOIN
               #Schedule s
               ON s.PersonId = e.PersonId and
                  s.SchedDate BETWEEN e.RangeBeginDate and e.RangeEndDate
          GROUP BY e.PersonID, e.RangeBeginDate, e.RangeEndDate
         ) ee
         ON ee.PersonId = e.PersonId and
            ee.RangeBeginDate = e.RangeBeginDate and
            ee.RangeEndDate = e.RangeEndDate;

尝试:

update Employees 
set HoursSched = (select isnull(sum(s.HoursSched ), 0) 
         from Schedule s 
         where s.person_id = t.person_id and s.SchedDate >= t.RangeBeginDate and s.SchedDate <= t.RangeEndDate )
from Employees t

Fiddle:

declare @t table(person_id int, sd date, ed date, h int)
declare @s table(person_id int, d date, h int)

insert into @t values
(1, '20120318', '20130317', null),
(1, '20130318', '20140317', null),
(1, '20140318', '20150317', null),
(2, '20120318', '20130317', null),
(2, '20130318', '20140317', null),
(2, '20140318', '20150110', null)

insert into @s values
(1, '20130321', 8),
(1, '20130322', 6),
(1, '20130323', 9),
(1, '20140515', 8),
(1, '20140615', 9),
(1, '20150122', 3),
(2, '20120329', 8),
(2, '20120401', 9),
(2, '20140509', 6),
(2, '20140510', 9)


update @t set h = (select isnull(sum(s.h), 0) from @s s where s.person_id = t.person_id and s.d >= t.sd and s.d <= t.ed)
from @t t

select * from @t

http://sqlfiddle.com/#!6/9eecb/1503