假设我有一个顾客表和一个购买表。每笔购买属于一个客户。我想在一个SELECT语句中获得所有客户及其最后一次购买的列表。最佳做法是什么?关于建立索引有什么建议吗?
请在回答中使用这些表/列名:
客户:id,姓名 购买:id, customer_id, item_id,日期
在更复杂的情况下,通过将最后一次购买放入customer表来对数据库进行非规范化(性能方面)是否有益?
如果(purchase) id保证按日期排序,是否可以使用LIMIT 1之类的东西来简化语句?
假设我有一个顾客表和一个购买表。每笔购买属于一个客户。我想在一个SELECT语句中获得所有客户及其最后一次购买的列表。最佳做法是什么?关于建立索引有什么建议吗?
请在回答中使用这些表/列名:
客户:id,姓名 购买:id, customer_id, item_id,日期
在更复杂的情况下,通过将最后一次购买放入customer表来对数据库进行非规范化(性能方面)是否有益?
如果(purchase) id保证按日期排序,是否可以使用LIMIT 1之类的东西来简化语句?
当前回答
先不讲代码,逻辑/算法如下:
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
*
FROM
customer c
OUTER APPLY(SELECT top 1 * FROM purchase pi
WHERE pi.customer_id = c.Id order by pi.Id desc) AS [LastPurchasePrice]
这是经常出现在StackOverflow上的“每组最多n个”问题的一个例子。
以下是我通常建议的解决方法:
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的特性来分析优化计划。例如,MySQL上的EXPLAIN。
有些人使用子查询而不是我上面展示的解决方案,但我发现我的解决方案更容易解决关系。
在SQL Server上你可以使用:
SELECT *
FROM customer c
INNER JOIN purchase p on c.id = p.customer_id
WHERE p.id = (
SELECT TOP 1 p2.id
FROM purchase p2
WHERE p.customer_id = p2.customer_id
ORDER BY date DESC
)
SQL Server小提琴:http://sqlfiddle.com/#!18/262fd / 2
在MySQL上你可以使用:
SELECT c.name, date
FROM customer c
INNER JOIN purchase p on c.id = p.customer_id
WHERE p.id = (
SELECT p2.id
FROM purchase p2
WHERE p.customer_id = p2.customer_id
ORDER BY date DESC
LIMIT 1
)
MySQL小提琴:http://sqlfiddle.com/#!9/202613/7
先不讲代码,逻辑/算法如下:
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
cc.pk_ID AS pk_Customer_ID,
cc.Customer_Name AS Customer_Name,
IFNULL(pp.pk_ID, '') AS fk_Purchase_ID,
IFNULL(pp.fk_Customer_ID, '') AS fk_Customer_ID,
IFNULL(pp.fk_Item_ID, '') AS fk_Item_ID,
IFNULL(pp.Purchase_Date, '') AS Purchase_Date
FROM customer cc
LEFT JOIN purchase pp ON (
SELECT zz.pk_ID
FROM purchase zz
WHERE cc.pk_ID = zz.fk_Customer_ID
ORDER BY zz.Purchase_Date DESC LIMIT 1) = pp.pk_ID
ORDER BY cc.pk_ID;