SQL:如何按日期范围连接两个表

时间:2017-03-22 10:06:09

标签: sql-server date join range

我有一个表,其中包含将Eployee Type分配给Work项的历史记录,如下所示:

| WorkItemID | EmployeeTypeID | ValidFrom               | ValidTo                 |
| 1          | 1              | 2017-03-01 12:19:20.000 | 2017-03-05 14:11:20.000 |
| 1          | 1              | 2017-03-10 17:00:20.000 | NULL                    |
| 1          | 2              | 2017-05-12 12:19:20.000 | 2017-05-29 14:11:20.000 |
| 1          | 2              | 2017-07-01 12:19:20.000 | NULL                    |
| 2          | 1              | 2017-01-01 15:19:20.000 | 2017-03-01 11:29:20.000 |
| 2          | 1              | 2017-04-03 16:19:20.000 | NULL                    |

NULL表示上次分配没有结束日期,并且仍然有效。 我还有一个表,其中包含为员工分配Eployee类型的历史记录:

| EmployeeID | EmployeeTypeID | ValidFrom               | ValidTo                 |
| 1          | 1              | 2017-01-01 12:19:20.000 | 2017-03-05 14:11:20.000 |
| 1          | 2              | 2017-03-05 14:11:20.000 | NULL                    |
| 2          | 1              | 2016-05-05 15:19:20.000 | 2017-03-01 11:29:20.000 |
| 2          | 2              | 2017-03-01 11:29:20.000 | NULL                    |

对于给定的EmployeeID和WorkItemID,我需要在这些日期范围内选择其EmployeeTypeID匹配的最小日期(如果有的话)。

例如,对于 EmployeeID = 1 WorkItemID = 1 ,其员工类型匹配的最短日期为 2017-03-01 (无视时间部分)。

如何编写SQL查询以正确连接这两个表并选择所需的日期?

3 个答案:

答案 0 :(得分:1)

以下方式似乎对我来说是正确的: 首先,我从表1中选择与日期范围匹配的表2的最小日期,它们也应该重叠:

DECLARE @MinDate1 datetime
DECLARE @MinDate2 datetime

SELECT @MinDate1 = 
(SELECT MIN(t1.ValidFrom)
FROM Table1 t1
JOIN Table2 t2 ON t1.EmployeeTypeID = t2.EmployeeTypeID
WHERE t1.WorkItemID = 1 AND t2.EmployeeID = 1
AND (t1.ValidFrom <= t2.ValidTo OR t2.ValidTo IS NULL)
AND (t1.ValidTo >= t2.ValidFrom OR t1.ValidTo IS NULL))

然后我从表2中选择与日期范围匹配的表1的最小日期,它们也应该重叠:

SELECT @MinDate2 = 
(SELECT MIN(t2.ValidFrom)
FROM Table1 t1
JOIN Table2 t2 ON t1.EmployeeTypeID = t2.EmployeeTypeID 
WHERE t1.WorkItemID = 1 AND t2.EmployeeID = 1
AND (t1.ValidFrom <= t2.ValidTo OR t2.ValidTo IS NULL)
AND (t1.ValidTo >= t2.ValidFrom OR t1.ValidTo IS NULL))

最后,我选择两个最大日期,即两个范围实际重叠且具有相同EmployeeTypeID的最小日期

SELECT CASE WHEN @MinDate1 > @MinDate2 THEN @MinDate1 ELSE @MinDate2 END AS MinOverlapDate

输出结果为:

| MinOverlapDate          |
| 2017-03-01 12:19:20.000 |

答案 1 :(得分:0)

所以它应该是这样的:

SELECT MIN(Date)
FROM table1 t1
JOIN table2 t2 ON t1.EmployeeTypeID = t2.EmployeeTypeID 
WHERE t1.EmployeeID = givenValue AND t2.WorkitemID = givenValue

但是如果你不知道结果是哪个表,你就不能为此写一个查询。

你应该做的是至少做3张或更多

  
      
  1. 将包含员工信息
  2.   
  3. 项目作业记录与工作相关的任何内容
  4.   
  5. 他们之间有一些联系(Emp 1有工作2)(Emp 2有工作4)等等
  6.   

您不能在两个表中拥有相同的值,而不知道您想从哪个数据获取数据!

或..您可以将其放入一个表中。

  

列:WorkItem | EmployeeID | EmployeeType |日期|日期

答案 2 :(得分:0)

实际上,我的变体仍然无法正常工作。每个EmployeeTypeID应逐个比较@ MinDate1和@ MinDate2。在那里它被独立地比较。

以下是解决此问题的正确变体:

SELECT MIN(CASE WHEN t1.ValidFrom > t2.ValidFrom THEN t1.ValidFrom ELSE t2.ValidFrom END) AS MinOverlapDate
            FROM Table1 t1
JOIN Table2 t2 ON t1.EmployeeTypeID = t2.EmployeeTypeID
WHERE t1.WorkItemID = 1 AND t2.EmployeeID = 1
AND (t1.ValidFrom <= t2.ValidTo OR t2.ValidTo IS NULL)
AND (t1.ValidTo >= t2.ValidFrom OR t1.ValidTo IS NULL)