我有用戶和標籤之間的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)完成此操作的最有效方法是什麼?
我有用戶和標籤之間的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)完成此操作的最有效方法是什麼?
除了其他很好的答案,它也可以檢查條件的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尚未註冊:)
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
,您將獲得定義了三個標籤中至少兩個的用戶。
你可以加入做到這一切......
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'
從技術上講,更高效的方式將使用適當的tag_id和self_oin只有user_has_tag表(3次)。但方法是正確的 – noonex 2009-11-05 15:53:32
那是肯定沒有最有效的,這將彙總所有記錄。例如。如果沒有用戶符合條件,將會做很多無用的工作 3 selfjoin是有效的方式 – noonex 2009-11-05 15:50:00
'@ noonex':對於真實世界的數據(大量用戶,大量標籤,高用戶標記基數),這是一種高效的辦法。 'tag_name IN(...)'是一個可優化的條件,它只會聚合帶有mathing標籤的記錄。如果你需要使查詢匹配'4'或'20'標籤呢?使用自連接時,您需要重寫查詢結構,只用參數「GROUP BY」。 – Quassnoi 2009-11-05 15:59:18