Рейтинг Postgres как столбца

#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: Вы сравнивали планы выполнения?