Правильно отформатируйте запрос ActiveRecord с помощью подзапроса в Postgres - PullRequest
0 голосов
/ 25 октября 2018

У меня есть рабочий SQL-запрос для Postgres v10.

SELECT * 
FROM 
    (
    SELECT DISTINCT ON (title) products.title, products.* 
    FROM "products" 
) subquery
WHERE subquery.active = TRUE AND subquery.product_type_id = 1
ORDER BY created_at DESC

С целью сделать запрос, основанный на столбце title, затем отфильтровать и упорядочить их.(Сначала я использовал подзапрос, так как казалось, что невозможно объединить DISTINCT ON с ORDER BY без подзапроса.

Я пытаюсь выразить указанный запрос в ActiveRecord.

Я делал

Product.select("*")
    .from(Product.select("DISTINCT ON (product.title) product.title, meals.*"))
    .where("subquery.active IS true")
    .where("subquery.meal_type_id = ?", 1)
    .order("created_at DESC")

, и это работает! Но это довольно грязно со строкой, где есть предложения. Есть лучший способ выразить этот запрос с ActiveRecord / Arel, или япросто работает в пределах того, что ActiveRecord может выразить?

1 Ответ

0 голосов
/ 26 октября 2018

Я думаю, что результирующий вызов ActiveRecord может быть улучшен.

Но я бы сначала начал улучшать исходный SQL-запрос.

Подзапрос

SELECT DISTINCT ON (title) products.title, products.* FROM products 

(я думаю, чтовместо meals должен быть products?) дубликат products.title, который там не нужен.Хуже того, он пропускает предложение ORDER BY.Как сказано в документации PostgreSQL :

Обратите внимание, что «первая строка» каждого набора непредсказуема, если только ORDER BY не используется для того, чтобы требуемая строка появилась первой

Я бы переписал подзапрос следующим образом:

SELECT DISTINCT ON (title) * FROM products ORDER BY title ASC 

, который дает нам вызов:

Product.select('DISTINCT ON (title) *').order(title: :asc)

В основном запросе where вызовы используют сгенерированный Rails псевдоним дляsubquery.Я бы не стал полагаться на внутреннее соглашение Rails о псевдонимах подзапросов, поскольку оно может измениться в любое время.Если вы не принимаете это во внимание, вы можете объединить эти условия в одном вызове where с синтаксисом аргументов в стиле хеш-функции.

Окончательный результат:

Product.select('*')
       .from(Product.select('DISTINCT ON (title) *').order(title: :asc))
       .where(subquery: { active: true, meal_type_id: 1 })
       .order('created_at DESC')
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...