2011-10-10 55 views
6

我有一組與標記集具有多對多關係的城市。用戶爲我提供了一組標籤(,其中可能包含重複項!),我需要返回匹配條目的列表,按相關性排序。通過多個標記進行相關排序搜索的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; 

非常感謝那些回答。

+0

用戶如何輸入標籤列表?他們是否鍵入一個逗號分隔的列表,然後將它們連接到查詢中? – mellamokb

回答

3

如果用戶列表以逗號分隔的列表形式出現,您可以嘗試將其轉換爲臨時表並加入。我不知道PosteGRE的relveant語法,所以這裏是在MySQL中的想法:

create temporary table usertags (tag_id int); 
insert usertags values (1),(3),(3),(4); 

SELECT name, COUNT(name) AS relevance 
FROM cities 
JOIN citytags on cities.id = citytags.city_id 
JOIN usertags on citytags.tag_id = usertags.tag_id 
GROUP BY name ORDER BY relevance DESC; 

轉換逗號分隔的列表,上面的代碼會像做了使用替換所有的,),(一樣簡單您的服務器端語言,然後將其嵌入到VALUES語句中以填充臨時表。

演示(MySQL的):http://www.sqlize.com/1qNThhD9tC

+0

哇! sqlize.com太棒了! 謝謝!這正是我需要的。 –

1

棒的所有標籤爲一個表,然後再加入其中,包括在名單中,而不是。

CREATE TABLE #input (
    tag_id INT NOT NULL 
) 
; 

INSERT INTO #input 
      SELECT 1 
UNION ALL SELECT 3 
UNION ALL SELECT 3 
UNION ALL SELECT 4 
; 

SELECT 
    city.name, 
    search.relevance 
FROM 
    city 
INNER JOIN 
(
    SELECT 
    city_id, 
    COUNT(*) AS relevance 
    FROM 
    citytags 
    INNER JOIN 
    #input 
     ON #input.tag_id = citytags.tag_id 
    GROUP BY 
    city_id 
) 
    AS search 
    ON search.city_id = city.id 
ORDER BY 
    search.relevance DESC 
; 
相關問題