我有一组与标记集具有多对多关系的城市。用户为我提供了一组标签(,其中可能包含重复项!),我需要返回匹配条目的列表,按相关性排序。通过多个标记进行相关排序搜索的SQL查询
数据
下面是一些样本数据来说明问题:
城市:
--------------------
| id | city |
--------------------
| 1 | Atlanta |
| 2 | Baltimore |
| 3 | Cleveland |
| 4 | Denver |
| 5 | Eugene |
--------------------
标签:
------
| id |
------
| 1 |
| 2 |
| 3 |
| 4 |
------
这些城市的标签是这样的:
Atlanta: 1, 2
Baltimore: 3
Cleveland: 1, 3, 4
Denver: 2, 3
Eugene: 1, 4
...所以CityTags表如下所示:
------------------------
| city_id | tag_id |
------------------------
| 1 | 1 |
| 1 | 2 |
| 2 | 3 |
| 3 | 1 |
| 3 | 3 |
| 3 | 4 |
| 4 | 2 |
| 4 | 3 |
| 5 | 1 |
| 5 | 4 |
------------------------
例1
如果用户给我的标签ID:1,3,3,4],我想算我有多少场比赛对每个标签,并返回像相关性排序的结果:
------------------------
| city | matches |
------------------------
| Cleveland | 4 |
| Baltimore | 2 |
| Eugene | 2 |
| Atlanta | 1 |
| Denver | 1 |
------------------------
由于克利夫兰匹配所有四个标签,它是第一,其次是巴尔的摩和尤金,每个有两个标签匹配,等等
示例2
另一个用于衡量的例子。对于搜索[2,2,2,3,4],我们会得到:
------------------------
| city | matches |
------------------------
| Denver | 4 |
| Atlanta | 3 |
| Cleveland | 2 |
| Baltimore | 1 |
| Eugene | 1 |
------------------------
SQL
如果我忽略重复的标签,那么它的琐碎:
SELECT name,COUNT(name) AS relevance FROM
(SELECT name FROM cities,citytags
WHERE id=city_id AND tag_id IN (1,3,3,4)) AS matches
GROUP BY name ORDER BY relevance DESC;
但那不是我需要的。我需要尊重重复。有人可以建议我怎么做到这一点?
Postgresql中的解决方案
啊哈!临时表是我需要的。 Postgresql让我用它的WITH语法来做到这一点。这里的解决方案:
WITH search(tag) AS (VALUES (1), (3), (3), (4))
SELECT name, COUNT(name) AS relevance FROM cities
INNER JOIN citytags ON cities.id=citytags.city_id
INNER JOIN search ON citytags.tag_id=search.tag
GROUP BY name ORDER BY relevance DESC;
非常感谢那些回答。
用户如何输入标签列表?他们是否键入一个逗号分隔的列表,然后将它们连接到查询中? – mellamokb