2011-06-29 19 views
0

我有一個帶有列名稱和標籤的mySQL表。如果一個人,「鮑勃」的標籤是「酷」,「有趣」和「幼稚」,我的桌子會有相應的行:(鮑勃,酷),(鮑勃,有趣)和(鮑勃,幼稚)。在mySQL中進行聯合和交叉的有效方法

有沒有一種有效的方法來根據帶有布爾查詢的標籤選擇人員?例如,在僞SQL中:SELECT名稱在哪裏人是(冷或不是有趣)而不是孩子。

我想我可以使用UNION,JOIN,也許一些子查詢一起破解一些東西,但我想知道是否有一種有效的方法來做到這一點。

編輯:

截至目前,我打算分發和,即((冷卻或不好笑)和稚氣未)=>(冷卻和稚氣未)OR(NOT滑稽和稚氣未)。然後,我可以確定每個部件與以下類似的東西:

SELECT DISTINCT a.name 
FROM `tags` AS a 
JOIN `tags` AS b ON (a.label='cool' AND a.name=b.name AND b.name NOT IN (
    SELECT name FROM `tags` WHERE label='funny')) 
JOIN `tags` AS c ON (a.name=c.name AND c.name='childish') 
# for "COOL AND NOT FUNNY AND CHILDISH" 

然後使用UNION將它們連接在一起。

+0

我認爲這樣做效率很高,我不知道有什麼其他方式可以使它更有效率, – adamjmarkham

回答

2

對於陰性檢查,最有效的方式是使用MINUS如下:

SELECT NAME 
FROM NAME_LABEL 
WHERE LABEL IN ('COOL') -- use IN for easy matching of multiple labels 
UNION 
SELECT NAME 
FROM NAME_LABEL NL 
WHERE NOT EXISTS (SELECT * FROM NAME_LABEL WHERE NAME = NL.NAME AND LABEL IN ('FUNNY')) 
MINUS 
SELECT NAME 
FROM NAME_LABEL 
WHERE LABEL IN ('CHILDISH'); 

MINUS的關鍵字來自第一查詢選擇不同行和出現在第二查詢。

性能將與索引更好的LABEL

CREATE INDEX NAME_LABEL_NAME ON NAME_LABEL(NAME); 

不幸的是, 「不好笑」 需要一個EXISTS子查詢。如果你使用連接,MySQL查詢優化器無論如何都會將它變成子查詢:(

+0

要創建任何「邏輯表達式」,那麼MINUS,INTERSECTION和UNION就足夠了嗎? –

+0

在效率方面WHERE NOT EXISTS和SELECT * MINUS FUNNY相比如何?對不起,我剛剛學習SQL。 –

+0

「EXISTS()」部分效率不高,'INTERSECTION'意味着你不需要的行集之間的'AND'邏輯,'UNION'只是將兩個行集合在一起,對它們進行排序並丟棄重複項(請注意'UNION ALL'不會丟棄重複項並保留行順序)'MINUS'從前面的行集中移除匹配的行。 – Bohemian