繁体   English   中英

组中重复的组中的 MIN 和 MAX 日期

[英]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
最终查询按EmpNoContractStart对数据进行分组,并采用每个组的最短结束日期。

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.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM