2017-06-05 98 views
0

我有一個SQL數據庫,其中存儲了與用戶關聯的用戶和標記(多對多關係)。我有經典模式與users表,tags表和「橋樑」表usertag哪個環節有標籤的用戶:SQL標記列表和標記過濾

users table: 
    +---------+---------+ 
    | Id  | Name | 
    +---------+---------+ 
    | 1  | Alice | 
    | 2  | Bob  | 
    | 3  | Carl | 
    | 4  | David | 
    | 5  | Eve  | 
    +---------+---------+ 

tags table: 
    +---------+---------+ 
    | Id  | Name | 
    +---------+---------+ 
    | 10  | Red  | 
    | 20  | Green | 
    | 30  | Blue | 
    +---------+---------+ 

usertag table: 
    +---------+---------+ 
    | UserId | TagId | 
    +---------+---------+ 
    | 2  | 10  | 
    | 2  | 20  | 
    | 1  | 30  | 
    | 4  | 20  | 
    | 4  | 10  | 
    | 4  | 30  | 
    | 5  | 10  | 
    +---------+---------+ 

現在,我做了一個查詢來檢索所有的用戶和他們的標籤,以逗號分隔場使用GROUP_CONCAT()功能:

SELECT u.*, GROUP_CONCAT(ut.tagid) as tags FROM users as u LEFT JOIN usertag as ut ON u.id = ut.userid GROUP BY u.id 

這給了我正確的輸出:

output: 
    +---------+---------+----------+ 
    | Id  | Name | Tags  | 
    +---------+---------+----------+ 
    | 1  | Alice | 30  | 
    | 2  | Bob  | 10,20 | 
    | 3  | Carl | (null) | 
    | 4  | David | 10,30,20 | 
    | 5  | Eve  | 10  | 
    +---------+---------+----------+ 

的問題是現在我想在其上實現標籤過濾,即能夠通過標籤(或多個標籤)查詢用戶。該過濾器應該使用AND運算符。

例如:獲取與標籤紅用戶(10)和綠色(20):

output: 
    +---------+---------+----------+ 
    | Id  | Name | Tags  | 
    +---------+---------+----------+ 
    | 2  | Bob  | 10,20 | 
    | 4  | David | 10,30,20 | 
    +---------+---------+----------+ 

又如:獲取與標籤紅用戶(10):

output: 
    +---------+---------+----------+ 
    | Id  | Name | Tags  | 
    +---------+---------+----------+ 
    | 2  | Bob  | 10,20 | 
    | 4  | David | 10,30,20 | 
    | 5  | Eve  | 10  | 
    +---------+---------+----------+ 

又如:獲取與標籤紅色(10),綠(20)藍(30)用戶:

output: 
    +---------+---------+----------+ 
    | Id  | Name | Tags  | 
    +---------+---------+----------+ 
    | 4  | David | 10,30,20 | 
    +---------+---------+----------+ 

我如何能實現這樣的查詢? This question上等都非常相似,它的實際工作,但它不與GROUP_CONCAT()領域這是我想保持,因爲它是

這裏的SQL小提琴處理http://sqlfiddle.com/#!9/291a5c/8

編輯

有人可能會想象,這個查詢工作:

獲取與標籤紅(10)和藍色的所有用戶(20):

SELECT u.name, GROUP_CONCAT(ut.tagid) 
    FROM users as u 
    JOIN usertag as ut ON u.id = ut.userid 
    WHERE ut.tagid IN (10,20) 
GROUP BY u.id 
    HAVING COUNT(DISTINCT ut.tagid) = 2 

其中給出:

output: 
    +---------+---------+----------+ 
    | Id  | Name | Tags  | 
    +---------+---------+----------+ 
    | 2  | Bob  | 10,20 | 
    | 4  | David | 10,20 | 
    +---------+---------+----------+ 

其用戶名明智正確的是(Bob和大衛),但Tags場從大衛的列表中缺少的標籤30!

+0

要檢查的標籤的最大數量是多少? –

+0

@vkp是16,不再有 –

回答

1

left jointags表中,幷包括在連接子句中搜索的ID,並檢查having中的計數。

SELECT u.id,u.name,GROUP_CONCAT(ut.tagid) as tags 
FROM users u 
LEFT JOIN usertag as ut ON u.id = ut.userid 
LEFT JOIN tags t ON t.id=ut.tagid AND t.ID IN (10,20,30) --change this as needed 
GROUP BY u.id,u.name 
HAVING COUNT(ut.tagid) >= COUNT(t.id) AND COUNT(t.id) = 3 --change this number to the number of tags 

如果有限制的值,另一個選項是使用FIND_IN_SET。例如,

SELECT * FROM (
SELECT u.*, GROUP_CONCAT(ut.tagid) as tags 
FROM users as u 
LEFT JOIN usertag as ut ON u.id = ut.userid 
GROUP BY u.id 
) T 
WHERE FIND_IN_SET('10',tags) > 0 AND FIND_IN_SET('20',tags) > 0 
+0

啊!好。這是否可以在SQLite上運行?如果我根本不需要標籤名稱,爲什麼需要引入「標籤」表? –

+0

這是因爲你需要來自該表的計數來進行比較。 –

+0

瞭解。你會推薦任何其他模式來簡化查詢嗎?這是可以在sqlite上工作的東西嗎? –