sql - 从连接的 MySQL 表中选择最新条目

标签 sql mysql join greatest-n-per-group

我的数据库中有库存数量信息。
1 个表,“stock”,包含产品 ID (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.sku ASC

我已经试过了:

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

但是没有效果

显示创建表库存:

CREATE TABLE stock (
stockid bigint(20) NOT NULL AUTO_INCREMENT,
sku char(25) NOT NULL,
quantity int(5) NOT NULL,
creationdate datetime NOT NULL,
stockfileid smallint(5) unsigned NOT NULL,
touchdate datetime NOT NULL,
PRIMARY KEY (stockid)
) ENGINE=MyISAM AUTO_INCREMENT=315169 DEFAULT CHARSET=latin1

显示创建表库存文件:

CREATE TABLE stockfile (
stockfileid smallint(5) unsigned NOT NULL AUTO_INCREMENT,
filename varchar(25) NOT NULL,
creationdate datetime DEFAULT NULL,
touchdate datetime DEFAULT NULL,
date datetime DEFAULT NULL,
begindate datetime DEFAULT NULL,
enddate datetime DEFAULT NULL,
PRIMARY KEY (stockfileid)
) ENGINE=MyISAM AUTO_INCREMENT=265 DEFAULT CHARSET=latin1

最佳答案

这是我们每周在 StackOverflow 上看到的常见问题“greatest-n-per-group”的示例。按照该标签查看其他类似的解决方案。

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;

如果 stockfile 中有多行具有最大日期,您将在结果集中同时获得它们。要解决此问题,您必须在 f2 上的连接中添加一些决胜条件。


感谢您添加 CREATE TABLE 信息。这在您询问 SQL 问题时非常有用。

我从 AUTO_INCREMENT 表选项中看到您在 stock 中有 315k 行,而在 stockfile 中只有 265 行。您的 stockfile 表是关系中的父表,stock 表是子表,其中有一列 stockfileid 引用 库存文件

所以您最初的问题具有误导性。您需要 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;

我假设您希望“最新”相对于 touchdate,因此如果您想改用 creationdate,您可以进行编辑。

我已经在连接中添加了一个术语,以便它解析关系。我知道您说过日期“实际上是独一无二的”,但俗话说,“one in a million is next Tuesday”。


好的,我想我明白你现在想做什么了。您需要每个 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;

这会自连接 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);

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

关于sql - 从连接的 MySQL 表中选择最新条目,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/1918827/

相关文章:

sql - SQL 插入时更新子索引

Php unlink() 不要删除图像文件

mysql - 与 NOT EXISTS 和子查询混淆

php - 在 mysql REGEXP 查询中转义单引号

php - 在我自己的设备上使用 Android 应用程序时 PHP 脚本出错

mysql - 数据丢失时删除行 2 joins away

php - 在 CodeIgniter 中加入查询

sql - 如何查看 SQL*Plus 中所有索引(包括隐式索引)的列表?

mysql - 如何最好地在 mysql 命令中使用 bash 中声明的变量?

sql - 如果一个或多个表中可能缺少该键,您能否在同一个键上连接三个表?