【发布时间】:2011-10-10 15:03:21
【问题描述】:
我有一组与一组标签具有多对多关系的城市。用户给了我一组标签(可能包含重复!),我需要返回一个匹配条目的列表,按相关性排序。
数据
这里有一些示例数据来说明问题:
城市:
--------------------
| 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 |
------------------------
由于 Cleveland 匹配了所有四个标签,所以它是第一个,其次是 Baltimore 和 Eugene,它们都有两个标签匹配,等等。
示例 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;
非常感谢那些回答的人。
【问题讨论】:
-
用户如何输入他们的标签列表?他们是否键入了一个逗号分隔的列表,然后您将其连接到查询中?
标签: sql postgresql