从已加入的MySQL表中选择最新条目

ske*_*rit 1 mysql sql join greatest-n-per-group

我的数据库中有库存数量信息.
1表,"stock",保存productid(sku)以及它来自的数量和文件名.

另一个表"stockfile"包含所有已处理的文件名以及日期.

现在我需要获得所有产品的最新库存数量值.

这给了我所有产品的所有库存数量(产生300.000条记录)

SELECT stock.stockid,stock.sku,stock.quantity,stockfile.filename,stockfile.date
FROM stock
INNER JOIN stockfile ON stock.stockfileid = stockfile.stockfileid
ORDER BY stock.skuASC

我已经尝试过了:

SELECT*FROM stock
INNER JOIN stockfile ON stock.stockfileid = stockfile.stockfileid
GROUP BY sku
HAVING stockfile.date = MAX(stockfile.date)
ORDER BY stock.skuASC

但它没有用

SHOW CREATE TABLE库存:

CREATE TABLE stock(
stockidbigint(20)NOT NULL AUTO_INCREMENT,
skuchar(25)NOT NULL,
quantityint(5)NOT NULL,
creationdatedatetime NOT NULL,
stockfileidsmallint(5)unsigned NOT NULL,
touchdatedatetime NOT NULL,
PRIMARY KEY(stockid)
)ENGINE = MyISAM AUTO_INCREMENT = 315169 DEFAULT CHARSET = latin1

SHOW CREATE TABLE stockfile:

CREATE TABLE stockfile(
stockfileidsmallint(5)unsigned NOT NULL AUTO_INCREMENT,
filenamevarchar(25)NOT NULL,
creationdatedatetime DEFAULT NULL,
touchdatedatetime DEFAULT NULL,
datedatetime DEFAULT NULL,
begindatedatetime DEFAULT NULL,
enddatedatetime DEFAULT NULL,
PRIMARY KEY(stockfileid)
)ENGINE = MyISAM AUTO_INCREMENT = 265 DEFAULT CHARSET = latin1

Bil*_*win 6

这是我们每周在StackOverflow上看到的经常被问到的" 每组最大 "问题的一个例子.按照该标记查看其他类似解决方案.

SELECT s.*, f1.*
FROM stock s
INNER JOIN stockfile f1
  ON (s.stockfileid = f1.stockfileid)
LEFT OUTER JOIN stockfile f2
  ON (s.stockfileid = f2.stockfileid AND f1.date < f2.date)
WHERE f2.stockfileid IS NULL;
Run Code Online (Sandbox Code Playgroud)

如果有多行stockfile具有最大日期,您将在结果集中获取它们.要解决此问题,您必须在连接中添加一些打破平局条件f2.


感谢您添加CREATE TABLE信息.当你提出SQL问题时,这非常有用.

我从AUTO_INCREMENT表格中看到你有315k行stock,只有265行stockfile.您的stockfile表是关系中的父表,stock表是子表,其中一列stockfileid引用了主键stockfile.

所以你原来的问题是误导性的.您想要最新的行stock,而不是最新的行stockfile.

SELECT f.*, s1.*
FROM stockfile f
INNER JOIN stock s1
  ON (f.stockfileid = s1.stockfileid)
LEFT OUTER JOIN stock s2
  ON (f.stockfileid = s2.stockfileid AND (s1.touchdate < s2.touchdate
      OR s1.touchdate = s2.touchdate AND s1.stockid < s2.stockid))
WHERE s2.stockid IS NULL;
Run Code Online (Sandbox Code Playgroud)

我假设你想要"最新"是相对的touchdate,所以如果你想使用它creationdate,你可以进行编辑.

我在连接中添加了一个术语,以便它解决关系.我知道你说日期"实际上是独一无二的",但俗话说" 下周二百万分之一 ".


好的,我想我明白你现在要做的是什么.您需要最新的每行sku,但date比较它们的位置在引用的表中stockfile.

SELECT s1.*, f1.*
FROM stock s1
JOIN stockfile f1 ON (s1.stockfileid = f1.stockfileid)
LEFT OUTER JOIN (stock s2 JOIN stockfile f2 ON (s2.stockfileid = f2.stockfileid))
  ON (s1.sku = s2.sku AND (f1.date < f2.date OR f1.date = f2.date AND f1.stockfileid < f2.stockfileid))
WHERE s2.sku IS NULL;
Run Code Online (Sandbox Code Playgroud)

这会自行连接stock到自己,寻找具有相同sku和更新的行date.如果找不到,则s1包含最新的行sku.并且每个实例stock都必须加入其中stockfile才能获得date.


关于优化的评论:我很难测试,因为我没有填充数据匹配你的表,但我猜你应该有以下索引:

CREATE INDEX stock_sku ON stock(sku);
CREATE INDEX stock_stockfileid ON stock(stockfileid);
CREATE INDEX stockfile_date ON stockfile(date);
Run Code Online (Sandbox Code Playgroud)

我建议使用EXPLAIN分析没有索引的查询,然后一次创建一个索引并重新分析,EXPLAIN以查看哪一个给出最直接的好处.