一尘不染

SQL连接:选择一对多关系中的最后一条记录

sql

假设我有一个客户表和一个采购表。每次购买都属于一个客户。我想在一份SELECT声明中列出所有客户以及他们最近一次购买的清单。最佳做法是什么?关于建立索引有什么建议吗?

请在您的答案中使用这些表/列的名称:

  • customer:id,name
  • purchase:id,customer_id,item_id,date
    并且在更复杂的情况下,通过将最后一次购买放入客户表中来对数据库进行非规范化(在性能方面)是否有益?

如果id保证按日期将(购买)排序,可以使用类似的语句来简化语句LIMIT 1吗?


阅读 354

收藏
2021-03-10

共1个答案

一尘不染

这是greatest-n-per-group在StackOverflow上经常出现的问题的一个示例。

这通常是我建议解决的方式:

SELECT c.*, p1.*
FROM customer c
JOIN purchase p1 ON (c.id = p1.customer_id)
LEFT OUTER JOIN purchase p2 ON (c.id = p2.customer_id AND 
    (p1.date < p2.date OR (p1.date = p2.date AND p1.id < p2.id)))
WHERE p2.id IS NULL;

说明:给定一行p1,就不应有p2同一位客户和更晚的日期(或者在有联系的情况下,更晚的日期id)。当我们发现这是事实时,则p1是该客户的最近一次购买。

对于指数,我会在创建复合指数purchase在列(customer_id,date,id)。这可以允许使用覆盖索引来完成外部联接。确保优化在您的平台上进行测试,因为优化取决于实现。使用RDBMS的功能来分析优化计划。例如EXPLAIN在MySQL上。

有些人使用子查询来代替我上面显示的解决方案,但是我发现我的解决方案可以更轻松地解决联系。

2021-03-10