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

ds97pgxw  于 2021-07-26  发布在  Java
关注(0)|答案(3)|浏览(315)

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

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缺乏经验,所以如果我能正确地解释的话,也许有很多众所周知的解决方案?
谢谢你的帮助!

oxosxuxt

oxosxuxt1#

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

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

table Tags 不需要。
但是如果你想要一个标签列表的结果,比如 '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
nxagd54h

nxagd54h2#

您可以执行条件排序:

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 表,然后使用 lateral join 检索属于目标列表的匹配标记的计数(我使用 ('A', 'B') 就像你的例子一样)。然后 order by 首先放置具有多个标记的项,并使用条件表达式按降序日期对其排序;只有一个标记的记录不被此排序条件考虑,而是属于按升序日期排序的最后一个排序条件。

yrefmtwq

yrefmtwq3#

尝试:

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

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

相关问题