【问题标题】:Postgresql: Sort Results based on maximum number of matches in table columnsPostgresql:根据表列中的最大匹配数对结果进行排序
【发布时间】:2016-08-18 14:59:00
【问题描述】:

根据评论编辑

我有 2 个表格 postscategories。结构及样本数据如下:

POSTS
ID    NAME                  DESCRIPTION              CATEGORY_ID
--  -----------------   -------------------          -----------
1   For Song Lovers     A post all about music            8
2   For Music Lovers    About passion of music            8
3   I love songs        Listing favourite songs           8
4   Rock Music          ImagineDragon                     6
5   Retro Music         Old choice musical themes         7

CATEGORIES
ID    NAME
--  -----------------
6   Artists
7   Entertainment
8   Music

我想以如下方式对记录进行排序:

  1. 在名称、描述和类别名称中匹配关键字的帖子首先出现,然后是
  2. 名称中带有匹配的关键字的帖子,描述后跟
  3. 帖子名称中包含匹配的关键字,后跟
  4. 描述中带有匹配的关键字的帖子,后跟
  5. 类别中具有匹配关键字的帖子

我想要的结果输出是(如果 keyword=music):

OUTPUT
---------
Post ID#2
Post ID#5
Post ID#4
Post ID#1
Post ID#3

我已经能够编写 5 个查询并将其组合成唯一的记录。但这不是优化的解决方案。这是我尝试过的:

(
SELECT "posts".* FROM "posts" INNER JOIN "categories" ON "categories"."id" = "posts"."category_id" WHERE posts.name iLIKE ('%music%') AND posts.description iLIKE ('%music%') AND categories.name iLIKE ('%music%')
+
SELECT "posts".* FROM "posts" WHERE posts.name iLIKE ('%music%') AND posts.description iLIKE ('%music%')
+
SELECT "posts".* FROM "posts"  WHERE posts.name iLIKE ('%music%')
+
SELECT "posts".* FROM "posts"  WHERE posts.description iLIKE ('%music%')
+
SELECT "posts".* FROM "posts" INNER JOIN "categories" ON "categories"."id" = "posts"."category_id" WHERE categories.name iLIKE ('%music%')
).uniq

我什至尝试编写单个查询,但这并没有返回我想要的结果(很明显我没有使用 GROUP OR COUNT)

SELECT posts.* FROM posts INNER JOIN categories ON categories.id = posts.category_id
WHERE (
  (posts.name iLIKE ('%music%') AND posts.description iLIKE ('%music%') AND categories.name iLIKE ('%music%'))
  OR (posts.name iLIKE ('%music%') AND posts.description iLIKE ('%music%'))
  OR (posts.name iLIKE ('%music%'))
  OR (posts.description iLIKE ('%music%'))
  OR (categories.name iLIKE ('%music%')))

请建议我如何使用上述 SQL 实现相同的效果。

环境详情:

数据库:PostgreSQL

版本:postgres (PostgreSQL) 9.4.5

【问题讨论】:

  • 我不知道 Postgresql,但也许您可以定义名称和描述列等以进行不区分大小写的排序规则?

标签: sql ruby-on-rails postgresql


【解决方案1】:

据我所知 PostgreSQL 支持布尔值,所以这应该符合您的描述,按单独的列排序:

SELECT posts.* FROM posts INNER JOIN categories ON categories.id = posts.category_id
WHERE  -- can be simplified to 
      LOWER(posts.name)        iLIKE ('%music%')
   OR LOWER(posts.description) iLIKE ('%music%')
   OR LOWER(categories.name)   iLIKE ('%music%')
ORDER BY -- FALSE probably sorts lower than TRUE, thus DESC
  LOWER(posts.name)        iLIKE ('%music%') DESC, posts.name,
  LOWER(posts.description) iLIKE ('%music%') DESC, posts.description
  LOWER(categories.name)   iLIKE ('%music%') DESC, categories.name

另外说明:iLike不区分大小写,那你为什么要申请LOWER呢?这应该返回相同的结果:

SELECT posts.* FROM posts INNER JOIN categories ON categories.id = posts.category_id
WHERE  -- can be simplified to 
      posts.name        iLIKE ('%music%')
   OR posts.description iLIKE ('%music%')
   OR categories.name   iLIKE ('%music%')
ORDER BY -- FALSE probably sorts lower than TRUE, thus DESC
   posts.name        iLIKE ('%music%') DESC, posts.name,
   posts.description iLIKE ('%music%') DESC, posts.description
   categories.name   iLIKE ('%music%') DESC, categories.name

现在将其与@JuanCarlosOropeza 的回答结合起来 :-)

【讨论】:

  • 感谢@dnoeth 的解决方案。抱歉,我很抱歉将LOWERiLIKE 一起使用。从这篇文章和原始代码中删除它。感谢您指出这一点。
  • 我认为你不需要与我的结合。我检查了一下,你是对的,你可以对布尔结果进行排序,然后 false 先去。并且.. DESC, posts.name, 让您的订单比我的更好。
  • 但是您可能应该考虑text search 那些iLike 可能不能使用任何索引并且如果数据库增长到很大可能会成为瓶颈。
  • @JuanCarlosOropeza:我还是更喜欢你的订单,它很简单。在 PostgreSQL 中,NULL 被认为高于任何值,如果你想对 DESC 进行排序,你可以添加 NULLS LAST
【解决方案2】:
 ORDER BY 
       CASE WHEN LOWER(posts.name) iLIKE ('%music%') THEN posts.name END,
       CASE WHEN LOWER(posts.description) iLIKE ('%music%') THEN posts.description END,
       CASE WHEN LOWER(categories.name) iLIKE ('%music%') THEN categories.name END,

【讨论】:

  • @dnoeth 是的,我刚看到,怪我的复制/粘贴技巧
【解决方案3】:

感谢@juan-carlos-oropeza 和@dnoeth 的回复。根据您的建议和 sn-p,我提出了以下建议并能够解决此问题

ORDER BY
  CASE WHEN posts.name iLIKE ('%music%') AND posts.description iLIKE ('%music%') AND categories.name iLIKE ('%music%') THEN 0 END,
  CASE WHEN posts.name iLIKE ('%music%') AND posts.description iLIKE ('%music%') THEN 1 END,
  CASE WHEN posts.name iLIKE ('%music%') THEN 2 END,
  CASE WHEN posts.description iLIKE ('%music%') THEN 3 END,
  CASE WHEN categories.name iLIKE ('%music%') THEN 4 END

【讨论】:

    猜你喜欢
    • 2013-01-25
    • 1970-01-01
    • 1970-01-01
    • 2015-04-27
    • 1970-01-01
    • 2013-04-30
    • 2021-06-06
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多