[英]MIN & MAX date in group where group repeats
我已经杀死了我的电子表格——谁知道查询 180k 行会太多。 :)
我已经计划好我的数据库替换,但是在规范化和清理电子表格数据时遇到了一些绊脚石。
我有一个类似于下面的数据表,称为RD1
。
工作日期 | 雇员编号 | 合同 |
---|---|---|
21 年 3 月 13 日 | 123 | 16 |
21 年 3 月 14 日 | 123 | 16 |
21 年 3 月 15 日 | 123 | 16 |
21 年 3 月 16 日 | 123 | 40 |
21 年 3 月 17 日 | 123 | 40 |
21 年 3 月 18 日 | 123 | 16 |
21 年 3 月 19 日 | 123 | 16 |
我正在尝试对表格进行分组,以便获得合同中每次更改的开始和结束日期。
我的决赛桌看起来像:
雇员编号 | 合同 | 开始日期 | 结束日期 |
---|---|---|---|
123 | 16 | 21 年 3 月 13 日 | 21 年 3 月 15 日 |
123 | 40 | 21 年 3 月 16 日 | 21 年 3 月 17 日 |
123 | 16 | 21 年 3 月 18 日 | 21 年 3 月 19 日 |
正如预期的那样,下面的 SQL 返回一个两行表。
SELECT EmpNo, Contract,
MIN(WorkDate) AS StartDate,
MAX(WorkDate) AS EndDate
FROM RD1
GROUP BY EmpNo, Contract
雇员编号 | 合同 | 开始日期 | 结束日期 |
---|---|---|---|
123 | 16 | 13/03/2021 | 2021 年 3 月 19 日 |
123 | 40 | 16/03/2021 | 17/03/2021 |
我对如何解决这个问题一无所知——自从我定期编写 SQL 以来已经十多年了。
任何帮助将不胜感激。
编辑
我的另一个想法是 WorkDate 是连续的,没有丢失任何日期,因此我可以将表格连接到自身几次以识别每个组的开始和结束。 现在这只是称为Query1
。
SELECT RD1.WorkDate,
RD1.EmpNo,
RD1.Contract,
IIF((RD1.EmpNo = RD2.EmpNo OR ISNULL(RD2.EmpNo)) AND
(RD1.Contract <> RD2.Contract OR ISNULL(RD2.Contract)),'Start',
IIF((RD1.EmpNo = RD3.EmpNo OR ISNULL(RD3.EmpNo)) AND
(RD1.Contract <> RD3.Contract OR ISNULL(RD3.Contract)),"End")) AS Identifier
FROM (RD1 LEFT JOIN RD1 RD2 ON RD1.EmpNo = RD2.EmpNo AND
RD1.WorkDate = RD2.WorkDate+1)
LEFT JOIN RD1 RD3 ON RD1.EmpNo = RD3.EmpNo AND
RD1.WorkDate = RD3.WorkDate-1
WHERE NOT ISNULL(IIF((RD1.EmpNo = RD2.EmpNo OR ISNULL(RD2.EmpNo)) AND
(RD1.Contract <> RD2.Contract OR ISNULL(RD2.Contract)),'Start',
IIF((RD1.EmpNo = RD3.EmpNo OR ISNULL(RD3.EmpNo)) AND
(RD1.Contract <> RD3.Contract OR ISNULL(RD3.Contract)),"End")))
这给出了下表:
工作日期 | 雇员编号 | 合同 | 标识符 |
---|---|---|---|
21 年 3 月 13 日 | 123 | 16 | 开始 |
21 年 3 月 15 日 | 123 | 16 | 结尾 |
21 年 3 月 16 日 | 123 | 40 | 开始 |
21 年 3 月 17 日 | 123 | 40 | 结尾 |
21 年 3 月 18 日 | 123 | 16 | 开始 |
21 年 3 月 19 日 | 123 | 16 | 结尾 |
然后我可以使用Query1
来获取开始/结束日期对,但这会将每个开始日期与每个结束日期连接起来。
SELECT T1.EmpNo,
T1.Contract,
T1.Start,
T2.End
FROM (SELECT EmpNo, Contract, WorkDate AS Start
FROM Query1 WHERE Identifier = 'Start') AS T1 LEFT JOIN
(SELECT EmpNo, Contract, WorkDate AS End FROM Query1 WHERE Identifier = 'End') AS T2
ON (T1.Start<=T2.End) AND (T1.EmpNo = T2.EmpNo)
雇员编号 | 合同 | 开始 | 结尾 |
---|---|---|---|
123 | 16 | 21 年 3 月 13 日 | 21 年 3 月 19 日 |
123 | 16 | 21 年 3 月 13 日 | 21 年 3 月 17 日 |
123 | 16 | 21 年 3 月 13 日 | 21 年 3 月 15 日 |
123 | 40 | 21 年 3 月 16 日 | 21 年 3 月 19 日 |
123 | 40 | 21 年 3 月 16 日 | 21 年 3 月 17 日 |
123 | 16 | 21 年 3 月 18 日 | 21 年 3 月 19 日 |
我想我需要它来获得大于开始日期的最小结束日期:
SELECT EmpNo,
Contract,
Start,
Min(End) AS MinOfEnd
FROM Query6
GROUP BY EmpNo, Contract, Start
ORDER BY Start
雇员编号 | 合同 | 开始 | MinOfEnd |
---|---|---|---|
123 | 16 | 21 年 3 月 13 日 | 15/03/2021 |
123 | 40 | 21 年 3 月 16 日 | 17/03/2021 |
123 | 16 | 21 年 3 月 18 日 | 2021 年 3 月 19 日 |
嗯,我似乎已经回答了......我会做一些检查,整理并添加它作为答案,除非有人能看到任何潜在的问题?
没有完全解决 - 单日将给出不正确的结束日期,而不是与开始日期相同的日期。
需要组标识符。 使用给定的示例:前 3 条记录是第 1 组,接下来的 2 条是第 2 组,最后 2 条是第 3 组。使用 Excel 后面的 VBA 填充列。 当合约值改变时,组 ID 会改变。
Sub SetGID()
Dim c As Integer, r As Integer, x As Integer, i As Integer
c = 1
r = 2
i = 1
x = Cells(r, 4)
Do While Not IsEmpty(Cells(r, 2))
Cells(r, 1) = i
r = r + 1
If Cells(r, 4) <> x Then
i = i + 1
x = Cells(r, 4)
End If
Loop
End Sub
或按原样将数据导入 Access 并运行类似的过程以更新表中的字段。 这将涉及打开记录集并循环其记录。
然后聚合查询对 GroupID 进行汇总。
SELECT GroupID, EmpNo, Contract,
MIN(WorkDate) AS StartDate,
MAX(WorkDate) AS EndDate
FROM RD1
GROUP BY GroupID, EmpNo, Contract
我从我的问题中遗漏的一点非常重要,那就是当EmpNo
开始时,他们将有连续的日期,直到他们完成时没有丢失日期。 考虑到这一点,您可以将表连接到自身以返回前一天和第二天的数据。
RD1
工作日期 | 雇员编号 | 合同 |
---|---|---|
21 年 3 月 13 日 | 123 | 16 |
21 年 3 月 14 日 | 123 | 16 |
21 年 3 月 15 日 | 123 | 20 |
21 年 3 月 16 日 | 123 | 40 |
21 年 3 月 17 日 | 123 | 40 |
21 年 3 月 18 日 | 123 | 40 |
21 年 3 月 19 日 | 123 | 16 |
查询8
第一个查询将有两个连接。 第一个将表与自身连接,因此 14-Mar-21 连接到 15-Mar-21,依此类推。 第二个再次将表与自身连接,以便 14-Mar-21 连接到 13-Mar-21 等。
通过这些连接,您可以检查当前合约值是否与前一天或下一天的值不同 - 因此确定每个块的开始和结束。
(我可能会稍微整理一下 WHERE 子句)
SELECT RD1.WorkDate,
RD1.EmpNo,
RD1.Contract,
IIF((RD1.EmpNo = RD2.EmpNo OR ISNULL(RD2.EmpNo)) AND
(RD1.Contract <> RD2.Contract OR ISNULL(RD2.Contract)),'Start') AS StartID,
IIF((RD1.EmpNo = RD3.EmpNo OR ISNULL(RD3.EmpNo)) AND
(RD1.Contract <> RD3.Contract OR ISNULL(RD3.Contract)),"End") AS EndID
FROM (RD1 LEFT JOIN RD1 RD2 ON RD1.EmpNo = RD2.EmpNo AND
RD1.WorkDate = RD2.WorkDate+1)
LEFT JOIN RD1 RD3 ON RD1.EmpNo = RD3.EmpNo AND
RD1.WorkDate = RD3.WorkDate-1
WHERE NOT ISNULL(IIF((RD1.EmpNo = RD2.EmpNo OR ISNULL(RD2.EmpNo)) AND
(RD1.Contract <> RD2.Contract OR ISNULL(RD2.Contract)),'Start',
IIF((RD1.EmpNo = RD3.EmpNo OR ISNULL(RD3.EmpNo)) AND
(RD1.Contract <> RD3.Contract OR ISNULL(RD3.Contract)),"End")))
工作日期 | 雇员编号 | 合同 | 起始编号 | 结束ID |
---|---|---|---|---|
21 年 3 月 13 日 | 123 | 16 | 开始 | |
21 年 3 月 14 日 | 123 | 16 | 结尾 | |
21 年 3 月 15 日 | 123 | 20 | 开始 | 结尾 |
21 年 3 月 16 日 | 123 | 40 | 开始 | |
21 年 3 月 17 日 | 123 | 40 | ||
21 年 3 月 18 日 | 123 | 40 | 结尾 | |
21 年 3 月 19 日 | 123 | 16 | 开始 | 结尾 |
查询9
下一个查询将每个开始日期连接到每个结束日期,前提是开始日期小于或等于结束日期。
SELECT T1.EmpNo,
T1.Contract,
T1.Start,
T2.End
FROM (
SELECT EmpNo, Contract, WorkDate AS Start
FROM Query8
WHERE NOT ISNULL(StartID)
) AS T1 LEFT JOIN
(
SELECT EmpNo, Contract, WorkDate AS [End]
FROM Query8
WHERE NOT ISNULL(EndID)) AS T2
ON (T1.Start<=T2.End) AND (T1.EmpNo = T2.EmpNo)
雇员编号 | 合同 | 开始 | 结尾 |
---|---|---|---|
123 | 16 | 21 年 3 月 13 日 | 21 年 3 月 19 日 |
123 | 16 | 21 年 3 月 13 日 | 21 年 3 月 18 日 |
123 | 16 | 21 年 3 月 13 日 | 21 年 3 月 15 日 |
123 | 16 | 21 年 3 月 13 日 | 21 年 3 月 14 日 |
123 | 20 | 21 年 3 月 15 日 | 21 年 3 月 19 日 |
123 | 20 | 21 年 3 月 15 日 | 21 年 3 月 18 日 |
123 | 20 | 21 年 3 月 15 日 | 21 年 3 月 15 日 |
123 | 40 | 21 年 3 月 16 日 | 21 年 3 月 19 日 |
123 | 40 | 21 年 3 月 16 日 | 21 年 3 月 18 日 |
123 | 16 | 21 年 3 月 19 日 | 21 年 3 月 19 日 |
查询10
最终查询按EmpNo
、 Contract
和Start
对数据进行分组,并采用每个组的最短结束日期。
SELECT EmpNo,
Contract,
Start,
Min(End) AS MinOfEnd
FROM Query9
GROUP BY EmpNo, Contract, Start
ORDER BY EmpNo, Start
雇员编号 | 合同 | 开始 | MinOfEnd |
---|---|---|---|
123 | 16 | 21 年 3 月 13 日 | 14/03/2021 |
123 | 20 | 21 年 3 月 15 日 | 15/03/2021 |
123 | 40 | 21 年 3 月 16 日 | 2021 年 3 月 18 日 |
123 | 16 | 21 年 3 月 19 日 | 2021 年 3 月 19 日 |
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.