【问题标题】:Select newest entry from a joined MySQL table从连接的 MySQL 表中选择最新条目
【发布时间】:2010-12-27 11:47:06
【问题描述】:

我的数据库中有库存数量信息。
1 个表,“stock”,包含 productid (sku) 以及数量和来自哪里的文件名。

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

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

这会多次提供所有产品及其所有库存数量(产生 300.000 条记录)

选择 stock.stockid、stock.sku、stock.quantity、stockfile.filename、stockfile.date
现货
在 stock.stockfileid = stockfile.stockfileid
上内部连接库存文件 通过stock.skuASC 订购

我已经试过了:

从库存中选择 *
在 stock.stockfileid = stockfile.stockfileid
上内部连接库存文件 按 sku 分组
拥有 stockfile.date = MAX(stockfile.date)
stock.skuASC 订购

但是没有用

显示创建表库存:

创建表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,
主键 (stockid)
) ENGINE=MyISAM AUTO_INCREMENT=315169 默认字符集=latin1

显示创建表库存文件:

CREATE TABLE stockfile (
stockfileid smallint(5) unsigned NOT NULL AUTO_INCREMENT,
filename varchar(25) NOT NULL,
creationdate datetime DEFAULT NULL,
touchdate datetime 默认为 NULL,
date datetime 默认为 NULL,
begindate datetime 默认为 NULL,
enddate datetime 默认为 NULL,
主键 (stockfileid)
) ENGINE=MyISAM AUTO_INCREMENT=265 默认字符集=latin1

【问题讨论】:

  • 请使用SHOW CREATE TABLE stockSHOW CREATE TABLE stockfile 的输出编辑您的问题。

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


【解决方案1】:

这是我们每周在 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 引用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;

我假设您希望“最新”相对于 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 重新分析,看看哪一个带来最直接的好处。

【讨论】:

  • 我知道,由于stackoverflow,我实际上已经解决了一个类似的问题。但是您的查询仍然给了我 315.000 个结果:/
  • 那么我猜每只股票的最大日期有很多关系。
  • 很多关系? “日期”字段在 stockfile 表中实际上是唯一的。每个日期,stock 表中可以有大约 100 条记录
  • 嗯,但我不能使用“库存”表中的触摸日期,唯一重要的日期是库存文件中的“日期”字段。 (touchdate 和 creationdate 是让我知道最初创建和最后编辑时间的字段。去年的库存文件今天可以重新导入,这将导致旧记录具有最高的 touchdate)
  • 这正是我的意思! :) (股票和股票文件可能是同一张表,但我教过尽可能多地去重)您的查询成功了。现在唯一的问题是大约需要 250 秒。有没有办法加快速度?新索引左右?
【解决方案2】:

用途:

SELECT DISTINCT s.stockid, 
       s.sku, 
       s.quantity, 
       sf.filename, 
       sf.date
  FROM STOCK s
  JOIN STOCKFILE sf ON sf.stockfileid = s.stockfileid
  JOIN (SELECT t.stockfileid,
               MAX(t.date) 'max_date'
          FROM STOCKFILE t
      GROUP BY t.stockfileid) x ON x.stockfileid = sf.stockfileid
                               AND x.max_date = sf.date

【讨论】:

  • 恐怕这仍然给了我所有 315.000 条记录。
  • 我更新为添加 DISTINCT,因为最可能的原因是由于 JOIN 导致行重复。
  • 嗯,即使是不同的,它仍然会给我所有重复的记录。
  • @Jelle:这是不可能的——DISTINCT 是 GROUP BY 的同义词——所有返回的行在某种程度上都是唯一的,即使它是一个列值。最可能的原因是您的平局基于最长日期。
  • @skerit: ties == 相似,有两个或多个匹配的记录。不像链接中那样绑定
【解决方案3】:
select *
from   stock
where  stockfileid in (
           select top 1 stockfileid
           from   stockfile
           order by date desc
       )

【讨论】:

  • 这不会按原样工作 - 您需要关联子查询。目前,子查询将只返回一行,并且您获得的是 stockfileid,而不是您真正想要的日期。
  • 这不是 MySQL 的有效 SQL:dev.mysql.com/doc/refman/5.4/en/select.html
  • 这也是 - 需要使用LIMIT,而不是TOP
  • 那么问题是每个库存文件都不包含完整的库存检查,因此特定产品的最新库存编号可能在任何文件中吗?这个问题似乎并不完全清楚。
  • 确实,并非所有内容都在最新的库存文件中。但即使是这样,我仍然需要获取最新的库存数量。
【解决方案4】:

有两种常见的方法可以实现这一点:子查询或自联接。

在 MySQL 网站上查看 this example of selecting the group-wise maximum

编辑,使用子查询的示例:

SELECT stock.stockid, stock.sku, stock.quantity,
       stockfile.filename, stockfile.date
FROM stock
INNER JOIN stockfile ON stock.stockfileid = stockfile.stockfileid
WHERE stockfile.date = (SELECT MAX(date) FROM stockfile);

【讨论】:

    猜你喜欢
    • 2019-01-17
    • 1970-01-01
    • 1970-01-01
    • 2021-10-31
    • 2013-10-11
    • 1970-01-01
    • 1970-01-01
    • 2020-07-19
    • 1970-01-01
    相关资源
    最近更新 更多