Sql 查找所有具有按升序时间排序的X标记的记录,但是,应首先对与大多数标记匹配的记录进行分组

Sql 查找所有具有按升序时间排序的X标记的记录,但是,应首先对与大多数标记匹配的记录进行分组,sql,postgresql,tags,Sql,Postgresql,Tags,好的,这有点难以解释,标题也不是最好的:/但是,基本上,我有3个表,我正在尝试编写一个查询,返回两个级别的排序。第一个由每行的“标记”数量决定,第二个由该行的创建时间决定 Table1: Items * ID * Name * CreatedAt Table2: Tags * ID * Name Table3: TaggedItems * TagID * ItemID 我想列出所有有一个或多个标记的项目,按创建时的升序排列。但是,这里是我遇到问题的地方,我希望排

好的,这有点难以解释,标题也不是最好的:/但是,基本上,我有3个表,我正在尝试编写一个查询,返回两个级别的排序。第一个由每行的“标记”数量决定,第二个由该行的创建时间决定

Table1: Items
  * ID
  * Name
  * CreatedAt

Table2: Tags
  * ID
  * Name

Table3: TaggedItems
  * TagID
  * ItemID
我想列出所有有一个或多个标记的项目,按创建时的升序排列。但是,这里是我遇到问题的地方,我希望排序基于与项目匹配的标记的数量,并且在该排序中,应用升序标准

那么,假设我有:

Item1 -> CreatedAt(0), Tags(A, B)
Item2 -> CreatedAt(0), Tags(A)
Item3 -> CreatedAt(1), Tags(B)
Item4 -> CreatedAt(1), Tags(A, B)

然后,搜索带有标记A和B的所有项目必须首先返回
Item1
Item4
,并按升序
CreatedAt
排序。然后
Item2
Item3
并按
CreatedAt
升序排序。因此,结果将是:

* Item1
* Item4
* Item2
* Item3
我没有SQL方面的经验,所以如果我能正确解释的话,可能有很多众所周知的解决方案


谢谢你的帮助

您可以执行条件排序:

select i.*, x.no_tags
from items
cross join lateral (
    select count(*) no_tags
    from taggedItems ti
    inner join tags t on t.id = ti.tagID
    where ti.ItemID = i.ID and t.name in ('A', 'B')
) x
order by
    (x.no_tags > 1) desc,
    case when x.no_tags > 1 then i.createdAt end desc,
    createdAt
查询从
items
表开始,然后使用
横向联接
来检索属于目标列表的匹配标记的计数(我在示例中使用了
('a','B')
)。然后,
orderby
将具有超过1个标记的项放在第一位,并使用条件表达式按降序日期对它们进行排序;只有一个标记的记录不被此排序标准考虑,而是属于按升序日期排序的最后一个排序标准。

请尝试:

    select i.id,i,name
    from Items i join TaggedItems ti on i.ID=ti.ItemID
    join Tags t on t.ID=ti.TagID
    group by i.id,i,name
    order by count(*),CreatedAt

短语
orderbycount(*)
适用于大多数数据库服务器。

使用
连接到
标记数据项
(以防项根本没有任何标记)并按项分组。
最后按标签数量降序排序,然后按日期排序:

SELECT i.name
FROM Items i LEFT JOIN TaggedItems t 
ON t.ItemID = i.ID
GROUP BY i.ID, i.Name
ORDER BY COUNT(t.TagID) DESC, i.CreatedAt
不需要表格
标签

但是如果您想要标签列表的结果,比如
'a'
'B'
,那么:

SELECT i.name
FROM Items i 
LEFT JOIN TaggedItems ti ON ti.ItemID = i.ID
LEFT JOIN Tags t ON t.ID = ti.TagID AND t.Name IN ('A', 'B')
GROUP BY i.ID, i.Name
ORDER BY COUNT(t.ID) DESC, i.CreatedAt