2016-06-22 1 views
1

Я работаю над небольшим компонентом форума для сайта, и я создаю страницу, где я хочу отображать каждую тему вместе с ее наивысшим рейтингом. Вот то, что таблицы выглядят следующим образом:Как выбрать самый высокий пост для каждой темы и связать их с учетом этой схемы?

POST  USER  TOPIC 
id   id  id 
date  name  title 
text  bio  date 
views     
likes 
topic_id 
author_id 

Моего запрос выглядит так:

select 
     u.id, u.name, u.bio, 
     p.id, p.date, p.text, p.views, p.likes, 
     t.id, t.title, t.date 
from 
     (select p.id, max(p.likes) as likes, p.topic_id 
     from post as p group by p.topic_id) as q 

     inner join post as p on q.id = p.id 
     inner join topic as t on t.id = q.topic_id 
     inner join user as u on u.id = p.author_id 

order by date desc; 

Одна из проблем, я с работой это жгуты «д». Postgresql не позволит мне запускать запрос «q», потому что он хочет, чтобы «p.id» находился в разделе «group by» или в агрегатной функции. Я попытался использовать «distinct on (p.id)», но я получил такое же сообщение об ошибке: p.id должен появиться в предложении GROUP BY или использоваться в агрегатной функции.

Без атрибута p.id я не могу объективно связать его с другими таблицами; есть ли другой способ сделать это?

+0

что, если их имеют отношения вы хотите и должны быть возвращены или просто 1 в теме? функции окна, такие как DENSE_RANK или ROW_NUMBER, получат то, что вы хотите – Matt

ответ

1
;WITH cte AS (
    SELECT 
     u.id AS UserId 
     ,u.name 
     ,u.bio 
     ,p.id AS PostId 
     ,p.[date] AS PostDate 
     ,p.text 
     ,p.views 
     ,p.Likes 
     ,t.id AS TopidId 
     ,t.title 
     ,t.[date] AS TopicDate 
     ,p.Likes 
     ,ROW_NUMBER() OVER (PARTITION BY t.id ORDER BY p.Likes DESC, p.[date] DESC) AS RowNum 
     ,DENSE_RANK() OVER (PARTITION BY t.id ORDER BY p.Likes DESC) AS RankNum 
    FROM 
     topic t 
     INNER JOIN post p 
     ON t.id = p.topic_id 
     INNER JOIN [user] u 
     ON p.author_id = u.id 
) 

SELECT * 
FROM 
    cte 
WHERE 
    RowNum = 1 

;

переключатель RowNum в RankNum, если вы хотите увидеть связи для наиболее понравившегося

1

Это общая потребность: при группировке, показать каждую группу первого/последний a ранжированных по некоторым другим критериям b. У меня нет имени для этого, но this seems to be the canonical question. Вы можете видеть, что есть много вариантов! Мое любимое решение, вероятно, в lateral join:

SELECT u.id, u.name, u.bio, 
     p.id, p.date, p.text, p.views, p.likes, 
     t.id, t.title, t.date 
FROM topic t 
LEFT OUTER JOIN LATERAL (
    SELECT * 
    FROM post 
    WHERE post.topic_id = t.id 
    ORDER BY post.likes DESC 
    LIMIT 1 
) p 
ON true 
LEFT OUTER JOIN "user" u 
ON p.author_id = u.id 
; 
1
SELECT 
    u.id AS uid, u.name, u.bio 
    , p.id AS pid, p."date" AS pdate, p.text, p.views, p.likes 
    , t.id AS tid, t.title, t."date" AS tdate 
FROM post p 
JOIN topic t ON t.id = p.topic_id 
JOIN user u ON u.id = p.author_id 
WHERE NOT EXISTS (SELECT * 
    FROM post nx 
    WHERE nx.topic_id = p.topic_id 
    AND nx.likes > p.likes) 
ORDER BY p."date" DESC 
    ;