PostgreSQL选择基于另一个带有顺序,限制和汇总的选择

时间:2019-07-02 21:05:58

标签: postgresql

我有一个像这样的表

书籍:

id | title      | rating_avr | visible
1  | 'Overlord' | 5          | true
2  | 'Avengers' | 10         | false

tags_books:

tag_id | book_id | likes
1      | 1       | 5
2      | 1       | 25
1      | 2       | 11

标签:

id | name
1  | 'Adventure'
2  | 'Drama'

现在,我需要加载带有LIMIT,ORDER和标记标签的书籍“ Drama”的书籍。

我设法通过查询实现了这一点:

SELECT b.id, b.title, b.rating_avr, json_agg(json_build_object('id', tb2.tag_id)) as tags
FROM books b
LEFT JOIN tags_books tb ON tb.book_id = b.id
LEFT JOIN tags_books tb2 ON tb2.book_id = b.id
WHERE tb.tag_id = 1 AND b.visible=true 
GROUP BY b.id ORDER BY b.rating_avr DESC LIMIT 5

我很好奇:

1)可以将同一张桌子连接两次吗?第一个用于where子句,第二个用于聚集标签。

2)如何根据喜欢点排序聚合标签?

3)这是正确的方法,还是有更好的方法?

1 个答案:

答案 0 :(得分:1)

奇怪的是,在查询中您没有使用表tags,尽管您想获取标签'Drama'的书,该标签是表tags中的一列。
我要做的是首先使用类似的查询获取所有标签为'Drama'的书籍的ID:

SELECT b.id FROM books b
INNER JOIN tags_books tb ON tb.book_id = b.id
INNER JOIN tags t ON t.id = tb.tag_id
WHERE t.name = 'Drama' AND b.visible=true

然后使用它来获得结果:

SELECT 
  b.id, b.title, b.rating_avr, 
  json_agg(json_build_object('id', tb.tag_id) order by tb.likes desc) as tags
FROM books b INNER JOIN tags_books tb
ON tb.book_id = b.id
WHERE b.id IN (
  SELECT b.id FROM books b
  INNER JOIN tags_books tb ON tb.book_id = b.id
  INNER JOIN tags t ON t.id = tb.tag_id
  WHERE t.name = 'Drama' AND b.visible=true
)
GROUP BY b.id, b.title, b.rating_avr
ORDER BY b.rating_avr DESC LIMIT 5

请参见demo
结果:

> id | title    | rating_avr | tags                    
> -: | :------- | ---------: | :-----------------------
>  1 | Overlord |          5 | [{"id" : 2}, {"id" : 1}]