我有一个相当复杂的查询,本质上是选择每种送货服务最便宜的送货服务价格。
为了获取每个送货服务的唯一记录,我使用 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/