#ruby-on-rails #ruby #postgresql
#ruby-on-rails #ruby #postgresql
Вопрос:
У меня есть следующий запрос:
SELECT name, rank() OVER (PARTITION BY user_id ORDER BY love_count DESC) AS position FROM items
И теперь я хотел бы сделать предложение where для функции rank():
SELECT name, rank() OVER (PARTITION BY user_id ORDER BY love_count DESC) AS position FROM items WHERE position = 1
То есть я хочу запросить наиболее любимый элемент для каждого пользователя. Однако это приводит к:
PGError: ERROR: column "position" does not exist
Кроме того, я использую Rails AREL для этого и хотел бы включить объединение в цепочку. Это код Ruby, который создает запрос:
Item.select("name, rank() OVER (PARTITION BY user_id ORDER BY love_count DESC) AS position").where("position = 1")
Есть идеи?
Ответ №1:
Вам нужно «обернуть» его в производную таблицу:
SELECT *
FROM (
SELECT name,
rank() OVER (PARTITION BY user_id ORDER BY love_count DESC) AS position
FROM items
) t
WHERE position = 1
Ответ №2:
Моей первой мыслью было «Использовать общее табличное выражение», подобное этому непроверенному.
WITH badly_named_cte AS (
SELECT name,
rank() OVER (PARTITION BY user_id
ORDER BY love_count DESC) AS position
FROM items
)
SELECT * FROM badly_named_cte WHERE position = 1;
Проблема, которую вы видите, связана с логическим порядком вычисления, требуемым стандартами SQL. SQL должен действовать так, как если бы псевдонимы столбцов (аргументы AS
оператора) не существовали до того, как будет вычислено предложение WHERE.
Комментарии:
1. 1 к производительности. Я не совсем уверен, почему, но CTE, похоже, примерно в 2 раза быстрее, чем вложенное соединение в принятом ответе.
2. @Keyo: Вы сравнивали планы выполнения?