mysql - 如何在 MySQL 和 Rails 中使用 SELECT DISTINCT ON

标签 mysql ruby-on-rails sqlite postgresql greatest-n-per-group

我有一个相当复杂的查询,本质上是选择每种送货服务最便宜的送货服务价格

为了获取每个送货服务的唯一记录,我使用 SQL 中的 DISTINCT 函数。此查询提供正确的结果:

DeliveryServicePrice.active.select('DISTINCT ON (delivery_service_id) *').order('delivery_service_id, price ASC')

(仅查询的一部分)

但是,这个查询似乎只适用于 PostgreSQL(考虑到 PostgreSQL 对 SQL 标准更加严格,我认为这很奇怪);它不适用于 MySQL 和 SQLite。我收到以下错误:

Mysql2::Error: You have an error in your SQL syntax; check the manual that corresponds to your MySQL server version for the right syntax to use near 'ON (delivery_service_id) * FROM `delivery_service_prices` WHERE `delivery_servi' at line 1: SELECT DISTINCT ON (delivery_service_id) * FROM `delivery_service_prices` WHERE `delivery_service_prices`.`active` = 1 AND (2808.0 >= min_weight AND 2808.0 <= max_weight AND 104.0 >= min_length AND 104.0 <= max_length AND 104.0 >= min_thickness AND 104.0 <= max_thickness) ORDER BY delivery_service_id, price ASC

我正在构建的应用程序是开源的,因此需要支持所有 3 种数据库类型。 如何在 Rails 框架语法中为 MySQL 和 SQLite 创建 DISTINCT ON 查询?

我使用的是 Rails 4.1。

资源

我之前的问题供引用:
How to select unique records based on foreign key column in Rails?

File and line number for where the query is being used.

完成答案

DeliveryServicePrice.select('delivery_service_prices.id').active.joins('LEFT OUTER JOIN delivery_service_prices t2 ON (delivery_service_prices.delivery_service_id = t2.delivery_service_id AND delivery_service_prices.price > t2.price)').where('t2.delivery_service_id IS NULL')

最佳答案

DISTINCT ON 是标准 SQL DISTINCT 的 Postgres 特定扩展。它们都不是“函数”,都是 SQL 关键字 - 尽管 DISTINCT ON 后面需要括号。让它看起来像一个函数。

有几种技术可以用标准 SQL 重写它,但它们都比较冗长。由于MySQL不支持窗口函数row_number()已经出来了。

详细信息和更多可能的查询技术:

NOT EXISTS 重写:

SELECT *
FROM   delivery_service_prices d1
WHERE  active = 1
AND    2808.0 BETWEEN min_weight AND max_weight
AND    104.0  BETWEEN min_length AND max_length
AND    104.0  BETWEEN min_thickness AND max_thickness
AND NOT EXISTS (
   SELECT 1
   FROM   delivery_service_prices d2
   WHERE  active = 1
   AND    2808.0 BETWEEN min_weight AND max_weight
   AND    104.0  BETWEEN min_length AND max_length
   AND    104.0  BETWEEN min_thickness AND max_thickness
   AND    d2.delivery_service_id = d1.delivery_service_id
   AND    d2.price < d1.price 
   AND    d2.<some_unique_id> < d1.<some_unique_id>  -- tiebreaker!
   )
ORDER  BY delivery_service_id
  • 如果同一个 delivery_service_id 可以有多行具有相同的价格,您需要添加一些独特的决胜局以避免每个 delivery_service_id 出现多个结果。至少如果您想要一个完全等效的查询。我的示例将选择具有最小 <some_unique_id> 的行来自每组受骗者。

  • DISTINCT ON 不同, ORDER BY此处是可选的。

关于mysql - 如何在 MySQL 和 Rails 中使用 SELECT DISTINCT ON,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/26894868/

相关文章:

ruby-on-rails - 两次之间的 Rails 查询

android - 在 android 中建立 sqlite 连接的最佳方法是什么?

objective-c - FMDB:添加新列并插入数据

java - sqlite - 如何在Where子句中使用变量?

mysql - 计算MySQL中两行数量之间的差异

ruby-on-rails - 具有嵌套属性的Rails表单(accepts_nested_attributes_for)

mysql - 除以子查询或在 SQL 中查找类别的比例

ruby-on-rails - 如何在 Rails 元素中分配不同的样式表?

mysql - 如何使用 mysqldump 跳过某些数据库表?

php - MySQL - LOAD DATA LOCAL INFILE - 如果数据库表名有连字符会出现问题