【问题标题】:Find all records that have X tags ordered by ascending time, BUT, the ones that match the most tags should be grouped first查找所有按时间升序排序的有 X 个标签的记录,但是,匹配最多标签的记录应该首先分组
【发布时间】:2020-06-15 21:50:53
【问题描述】:

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

Table1: Items
  * ID
  * Name
  * CreatedAt

Table2: Tags
  * ID
  * Name

Table3: TaggedItems
  * TagID
  * ItemID

我想按创建时的升序列出所有具有 1 个或多个标签的项目。但是,这就是我遇到问题的地方,我希望排序基于与项目匹配的标签数量,并在该排序中应用升序标准。

所以,假设我有:

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

然后搜索带有标签 A 和 B 的所有项目必须首先返回 Item1Item4 并按升序排列 CreatedAt。然后Item2Item3 并按CreatedAt 升序排列。所以结果是:

* Item1
* Item4
* Item2
* Item3

我对 SQL 缺乏经验,所以如果我解释正确的话,也许有众所周知的解决方案?

感谢任何帮助!

【问题讨论】:

    标签: sql postgresql tags


    【解决方案1】:

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

    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
    

    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
    

    【讨论】:

      【解决方案2】:

      您可以进行条件排序:

      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 将超过 1 个标签的项目放在首位,并使用条件表达式将它们按日期降序排序;只有一个标签的记录不会被此排序标准考虑在内,属于最后一个排序标准,即按日期升序排序。

      【讨论】:

        【解决方案3】:

        试试:

            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(*)适用于大多数数据库服务器。

        【讨论】:

          猜你喜欢
          • 2022-10-09
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 2018-03-06
          • 2022-01-24
          相关资源
          最近更新 更多