2009-11-05 61 views
5

我有用戶和標籤之間的m:n關係。一個用戶可以有m個標籤,一個標籤可以屬於n個用戶。表是這個樣子:SQL SELECT與m:n的關係

USER: 
ID 
USER_NAME 

USER_HAS_TAG: 
USER_ID 
TAG_ID 

TAG: 
ID 
TAG_NAME 

比方說,我需要選擇的所有用戶,誰都有標籤「蘋果」,「橙色」和「香蕉」。使用SQL(MySQL DB)完成此操作的最有效方法是什麼?

回答

4

除了其他很好的答案,它也可以檢查條件的WHERE子句:

select * 
from user u 
where 3 = (
    select count(distinct t.id) 
    from user_has_tag uht 
    inner join tag t on t.id = uht.tag_id 
    where t.name in ('apple', 'orange', 'banana') 
    and uht.user_id = u.userid 
) 

count(distinct ...)確保標籤只計算一次,即使用戶有多個「香蕉」標籤。

順便說一句,該網站fruitoverflow.com尚未註冊:)

8
SELECT u.* 
FROM (
     SELECT user_id 
     FROM tag t 
     JOIN user_has_tag uht 
     ON  uht.tag_id = t.id 
     WHERE tag_name IN ('apple', 'orange', 'banana') 
     GROUP BY 
       user_id 
     HAVING COUNT(*) = 3 
     ) q 
JOIN user u 
ON  u.id = q.user_id 

通過消除HAVING COUNT(*),你OR而不是AND(雖然它不會是最有效的方法)

通過與2更換3,你有精確定義二三標籤的用戶。

通過將= 3替換爲>= 2,您將獲得定義了三個標籤中至少兩個的用戶。

+0

那是肯定沒有最有效的,這將彙總所有記錄。例如。如果沒有用戶符合條件,將會做很多無用的工作 3 selfjoin是有效的方式 – noonex 2009-11-05 15:50:00

+0

'@ noonex':對於真實世界的數據(大量用戶,大量標籤,高用戶標記基數),這是一種高效的辦法。 'tag_name IN(...)'是一個可優化的條件,它只會聚合帶有mathing標籤的記錄。如果你需要使查詢匹配'4'或'20'標籤呢?使用自連接時,您需要重寫查詢結構,只用參數「GROUP BY」。 – Quassnoi 2009-11-05 15:59:18

0
SELECT * 
FROM USER u 
INNER JOIN USER_HAS_TAG uht 
ON u.id = uht.user_id 
INNER JOIN TAG t 
ON uht.TAG_ID = t.ID 
WHERE t.TAG_NAME IN ('apple','orange','banana') 
+0

這不起作用 – tputkonen 2009-11-05 14:36:27

+0

如果你想要標籤爲'apple','orange'或'banana'的用戶,但不是全部三個, – MarthyM 2016-06-29 09:06:11

3

你可以加入做到這一切......

select u.* 
from user u 

inner join user_has_tag ut1 on u.id = ut1.user_id 
inner join tag t1 on ut1.tag_id = t1.id and t1.tag_name = 'apple' 

inner join user_has_tag ut2 on u.id = ut2.user_id 
inner join tag t2 on ut2.tag_id = t2.id and t2.tag_name = 'orange' 

inner join user_has_tag ut3 on u.id = ut3.user_id 
inner join tag t3 on ut3.tag_id = t3.id and t3.tag_name = 'banana' 
+0

從技術上講,更高效的方式將使用適當的tag_id和self_oin只有user_has_tag表(3次)。但方法是正確的 – noonex 2009-11-05 15:53:32