【问题标题】:MySQL - select distinct values against a range of columnsMySQL - 针对一系列列选择不同的值
【发布时间】:2012-07-23 14:50:49
【问题描述】:

下表将存储不同货币之间的汇率随时间变化:

CREATE TABLE `currency_exchange` (
 `id` int(11) NOT NULL AUTO_INCREMENT,
 `currency_from` int(11) DEFAULT NULL,
 `currency_to` int(11) DEFAULT NULL,
 `rate_in` decimal(12,4) DEFAULT NULL,
 `rate_out` decimal(12,4) DEFAULT NULL,
 `exchange_date` datetime DEFAULT NULL,
 PRIMARY KEY (`id`)
) ENGINE=MyISAM DEFAULT CHARSET=utf8 COLLATE=utf8_unicode_ci

如何查询它以获取最新汇率列表?

它本质上是将组合的 currency_fromcurrency_to 列识别为不同的汇率,然后找到日期最近的那个。

例如,假设我的数据如下:

INSERT INTO currency_exchange (id, currency_from, currency_to, rate_in, rate_out, exchange_date) VALUES
(1, 1, 2, 0.234, 1.789, '2012-07-23 09:24:34'),
(2, 2, 1, 0.234, 1.789, '2012-07-24 09:24:34'),
(3, 2, 1, 0.234, 1.789, '2012-07-24 09:24:35'),
(4, 1, 3, 0.234, 1.789, '2012-07-24 09:24:34');

我希望它选择行 ID:

  • 1 - 作为货币 1 和 2 之间的最新汇率
  • 3 - 作为货币 2 和 1 之间的最新汇率
  • 4 - 作为货币 1 和 3 之间的最新汇率

【问题讨论】:

  • 很遗憾您没有使用 PostgreSQL...在那里您可以使用SELECT DISTINCT ON (currency_from, currency_to) * FROM currency_exchange ORDER BY currency_from, currency_to, exchange_date DESC。 MySQL 缺少表达此功能的语法。
  • @cdhowie 另外,有时人们只想坚持使用标准 SQL,因此 PostgreSQL 扩展可能无论如何都不能接受。

标签: mysql distinct


【解决方案1】:

以下查询应该有效:

SELECT ce.*
FROM currency_exhcnage ce
LEFT JOIN currency_exchange newer
    ON (newer.currency_from = ce.currency_from
    AND newer.currency_to = ce.currency_to
    AND newer.exchange_date > ce.exchange_date)
WHERE newer.id IS NULL

执行 self-LEFT JOIN 的技巧是避免使用子查询,如果您有大型数据集,这可能会非常昂贵。它本质上是在寻找不存在“较新”记录的记录。

或者,您可以选择更简单的(尽管它可能(或可能不会,如 cmets 中所述)更慢):

SELECT *
FROM currency_exchange ce
NATURAL JOIN (
    SELECT currency_from, currency_to, MAX(exchange_date) AS exchange_date
    FROM currency_exchange
    GROUP BY currency_from, currency_to
) AS most_recent

【讨论】:

  • 请注意,并非所有子查询都是低效的。在某些情况下,查询计划器能够优化子查询。如果性能是一个问题,应该使用EXPLAIN 来优化查询;这适用于所有查询,而不仅仅是包含子查询的查询。
  • “Y 的最小值/最大值的 X 值”类型的查询通常对 MySQL 优化器的优化机会相对较少......
  • 当然,我只是指出子查询并不总是低效的。我编写了一个 SQL 语句,其中包含三个连接子查询,针对同一个在 任何查询都可能很昂贵。
  • 非常感谢你们两位,他们提供了一个很好的答案并帮助我了解它是如何工作的。而且你这样做的速度非常惊人:)
  • @cdhowie 我按照你的意思理解了。我打算对特定用例的子查询性能发表评论。它仍然很有价值。
【解决方案2】:

在动态查询中插入 $currency_from 和 $currency_to 的值。 下面的查询会返回离当前时间最近的行

SELECT id FROM currency_exchange WHERE currency_from='$currency_from' AND currency_to='$currency_to' ORDER BY ABS( DATEDIFF( exchange_date, now() ) ) LIMIT 1 

【讨论】:

  • 如果他想找到所有个货币对的id,却事先不知道存在哪些货币对怎么办?
  • 是的 - 我可以轻松获取给定 fromto 货币的最新记录。我想获取 from 和 to 的所有组合的列表。不过谢谢:)
猜你喜欢
  • 1970-01-01
  • 2014-01-27
  • 2021-03-30
  • 2012-01-05
  • 1970-01-01
  • 1970-01-01
  • 2012-05-25
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多