【问题标题】:Joining most recent record based on the date in another record根据另一条记录中的日期加入最近的记录
【发布时间】:2019-10-14 15:59:48
【问题描述】:

我有两张桌子 - 我们称它们为 weekcontract,如下所示:

Week                                    Contract    
emp_id | starting   | data1 |  ...   emp_id | from_date  | data2 | ...
-------|------------|-------|--      -------|------------|-------|--
12     | 2019-01-08 | abcd  |        12     | 2018-08-01 | efgh  | 
12     | 2019-01-15 | abcd  |        13     | 2018-10-02 | efgh  | 
12     | 2019-01-22 | abcd  |        13     | 2019-01-15 | ijkl  | 
13     | 2019-01-08 | abcd  |        13     | 2019-03-19 | mnop  | 
13     | 2019-01-15 | abcd  |        14     | 2017-02-02 | efgh  | 
13     | 2019-01-22 | abcd  |        15     | 2018-01-19 | efgh  | 

week.starting 字段是一个相当固定间隔的日期(时间设置为午夜的日期时间)。 (emp_id,starting) 的具体组合是唯一的。 from_date 字段也是记录contract 记录适用的开始期间的日期。这可能是在未来,所以我们不能只做一个MAX(from) 并为每个员工获得正确的合同。目前, (emp_id, from_date) 是唯一的,但我不想依赖它。 week.startingcontract.from_date 可以相同。

我想要一个返回整个 week 记录的查询,并且对于每个记录,任何 contract 的记录当时处于活动状态 - 也就是说,from_date 最大但仍小于或等于的记录到week.starting。如果我有特定的一周,获得这份合同是一个非常简单的最大 n-per-group 问题:

SELECT * FROM contract 
WHERE contract.emp_id = @emp_id AND contract.from_date <= @starting
ORDER BY contract.from_date DESC
LIMIT 1

但我不知道如何在查询中执行此操作以获取week 中的每条记录。我的特定障碍组合意味着我无法找到答案,尽管这是一组常见的问题。我似乎无法将week.starting 传递到子查询中,而且我似乎也无法在连接中使用 LIMIT 。到目前为止,我最好的尝试最终加入了所有不到一周的合同。

什么查询会返回我正在寻找的结果?

emp_id | starting   | from_date  | data1 | data2 | ...
-------|------------|------------|-------|-------|--
12     | 2019-01-08 | 2018-08-01 | abcd  | efgh  |
12     | 2019-01-15 | 2018-08-01 | abcd  | efgh  |
12     | 2019-01-22 | 2018-08-01 | abcd  | efgh  |
13     | 2019-01-08 | 2018-10-02 | abcd  | efgh  |
13     | 2019-01-15 | 2019-01-15 | abcd  | ijkl  |
13     | 2019-01-22 | 2019-01-15 | abcd  | ijkl  |

【问题讨论】:

  • 您提供条件的依据是什么,例如:for emp_id = 13 13 --> 2019-01-08 ---> 2018-10-02 13 --> 2019-01-15 - -> 2019-01-15 13 --> 2019-01-22 --> 2019-01-15
  • 抱歉,我在示例表中打错了字。有些日期应该是 2019 年,而不是 2018 年。

标签: sql postgresql date greatest-n-per-group


【解决方案1】:

在 Postgres 中,您可以使用横向连接:

select w.*, c.*
from weeks w left join lateral
     (select c.*
      from contract c
      where c.emp_id = w.emp_id and
            c.from_date <= w.starting
      order by c.from_date desc
      fetch first 1 row only
     ) c;

【讨论】:

    【解决方案2】:

    您应该能够使用窗口函数在过滤未来合约并分配排名后及时对合约进行排序。然后你可以选择排名最高的最新的。

    尚未对此进行测试,但应该类似于:

    select * from (
        select w.*, c.from_date, c.data2,
            row_number() over (partition by c.emp_id, w.starting order by c.from_date desc) as latest
        from week w
        join contract c on c.emp_id = w.emp_id and c.from_date <= w.starting
    ) as sub where latest = 1
    

    【讨论】:

    • 您可以使用 first_value(data2) 而不是 row_number() 来消除对外部选择子句的需要,请参阅official documentation
    • First_value 将该结果应用于窗口框架中的每一行。然后你仍然需要检查 first_value=from_date 的位置。它不会为您进行过滤。这也可能会引入欺骗,因为可能匹配不止一次。
    • 你是对的。如果您使用partition by c.emp_id, w.starting,您将获得 OP 所期望的准确输出(员工每周的合同)。
    • 想指出,在某些情况下使用 first_value 返回所有匹配的行可能是可取的。
    • 我刚刚在我们的开发数据库上尝试过这个,效果很好。
    猜你喜欢
    • 1970-01-01
    • 2022-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2015-11-05
    • 2019-03-29
    相关资源
    最近更新 更多