假设我有一个顾客表和一个购买表。每笔购买属于一个客户。我想在一个SELECT语句中获得所有客户及其最后一次购买的列表。最佳做法是什么?关于建立索引有什么建议吗?

请在回答中使用这些表/列名:

客户:id,姓名 购买:id, customer_id, item_id,日期

在更复杂的情况下,通过将最后一次购买放入customer表来对数据库进行非规范化(性能方面)是否有益?

如果(purchase) id保证按日期排序,是否可以使用LIMIT 1之类的东西来简化语句?


当前回答

另一种方法是在你的连接条件中使用NOT EXISTS条件来测试以后的购买:

SELECT *
FROM customer c
LEFT JOIN purchase p ON (
       c.id = p.customer_id
   AND NOT EXISTS (
     SELECT 1 FROM purchase p1
     WHERE p1.customer_id = c.id
     AND p1.id > p.id
   )
)

其他回答

先不讲代码,逻辑/算法如下:

Go to the transaction table with multiple records for the same client. Select records of clientID and the latestDate of client's activity using group by clientID and max(transactionDate) select clientID, max(transactionDate) as latestDate from transaction group by clientID inner join the transaction table with the outcome from Step 2, then you will have the full records of the transaction table with only each client's latest record. select * from transaction t inner join ( select clientID, max(transactionDate) as latestDate from transaction group by clientID) d on t.clientID = d.clientID and t.transactionDate = d.latestDate) You can use the result from step 3 to join any table you want to get different results.

请尝尝这个,

SELECT 
c.Id,
c.name,
(SELECT pi.price FROM purchase pi WHERE pi.Id = MAX(p.Id)) AS [LastPurchasePrice]
FROM customer c INNER JOIN purchase p 
ON c.Id = p.customerId 
GROUP BY c.Id,c.name;

如果你正在使用PostgreSQL,你可以使用DISTINCT ON来查找组中的第一行。

SELECT customer.*, purchase.*
FROM customer
JOIN (
   SELECT DISTINCT ON (customer_id) *
   FROM purchase
   ORDER BY customer_id, date DESC
) purchase ON purchase.customer_id = customer.id

PostgreSQL Docs - Distinct On

注意,DISTINCT ON字段——这里是customer_id——必须匹配ORDER BY子句中最左边的字段。

注意:这是一个非标准条款。

我发现这条线索可以解决我的问题。

但当我尝试时,它们的表现很低。Bellow是我对更好的性能的建议。

With MaxDates as (
SELECT  customer_id,
                MAX(date) MaxDate
        FROM    purchase
        GROUP BY customer_id
)

SELECT  c.*, M.*
FROM    customer c INNER JOIN
        MaxDates as M ON c.id = M.customer_id 

希望这对你有所帮助。

在SQLite上测试:

SELECT c.*, p.*, max(p.date)
FROM customer c
LEFT OUTER JOIN purchase p
ON c.id = p.customer_id
GROUP BY c.id

max()聚合函数将确保从每个组中选择最新的购买(但假设日期列的格式是max()给出最新的—通常情况下是这样)。如果你想处理同一日期的购买,那么你可以使用max(p。目前为止,p.id)。

在索引方面,我将使用一个关于购买的索引(customer_id,日期,[您想在选择中返回的任何其他购买列])。

LEFT OUTER JOIN(相对于INNER JOIN)将确保从未购买过的客户也包括在内。