2017-10-06 52 views
0

使用3個表(線程,標記,ThreadTag),我試圖選擇具有查詢中提供的所有標記的線程。在這個例子中,我需要有「聯邦快遞」和「運費」標籤的線程(S),所以預期的結果是2行:線程ID 1和4在多對多行中選擇與輸入完全匹配的行

線程表

+----------+----------------------------------+ 
| ThreadID |   ThreadTitle   | 
+----------+----------------------------------+ 
|  1 | Can I choose Fedex for shipping? | 
|  2 | Is Shipping Free     | 
|  3 | Can I use a credit card?   | 
|  4 | Does Fedex ship next day?  | 
|  5 | Is Fedex reliable?    | 
+----------+----------------------------------+ 

標籤表

+-------+-------------+ 
| TagID | TagName | 
+-------+-------------+ 
|  1 | shipping | 
|  2 | fedex  | 
|  3 | ups   | 
|  4 | price  | 
|  5 | free  | 
|  6 | credit card | 
+-------+-------------+ 

ThreadTag表

+----------+-------+ 
| ThreadID | TagID | 
+----------+-------+ 
|  1 |  1 | 
|  1 |  2 | 
|  1 |  3 | 
|  2 |  1 | 
|  2 |  5 | 
|  3 |  6 | 
|  4 |  1 | 
|  4 |  2 | 
|  5 |  2 | 
+----------+-------+ 

這裏是我想出了代碼:

WITH ThreadsWithMatchingTags AS (
    SELECT ThreadID 
    FROM ThreadTag tt 
    INNER JOIN Tag t on tt.TagID = t.TagID 
    WHERE TagName IN ('shipping', 'fedex') 
    GROUP BY ThreadID 
    HAVING COUNT(ThreadID) = 2 
) 
SELECT * 
FROM Thread 
WHERE ThreadID IN (SELECT ThreadID FROM ThreadsWithMatchingTags) 

OUTPUT:

+----------+----------------------------------+ 
| ThreadID |   ThreadTitle   | 
+----------+----------------------------------+ 
|  1 | Can I choose Fedex for shipping? | 
|  4 | Does Fedex ship next day?  | 
+----------+----------------------------------+ 

其作品,但有一定有一個更好的辦法。

+3

爲什麼?你的方法很好。 –

+0

您可以使用內部連接而不是IN()和子查詢來代替CTE,但執行計劃可能非常相似 –

+1

您需要在羣組中使用'GROUP BY ThreadID HAVING COUNT(ThreadID)= 2'嗎? – Amit

回答

1

「更好」是主觀的,我總是比較優化器的輸出,因爲您的解決方案沒有任何問題。

話雖如此,我會做這樣的事情: -

select 
    a.* 
from 
    Thread a 
where 
    (
    select 
     count(*) 
    from 
     Tag  b, 
     ThreadTag c 
    where 
     c.ThreadID = a.ThreadID and 
     b.TagID = c.TagID and 
     b.TagName in ('shipping', 'fedex') 
    ) = 2; 
2

下面是寫你查詢的其他方式。

SELECT * from Thread th 
WHERE(SELECT COUNT(*) from Tag ta, ThreadTag tt 
WHERE ta.TagID = tt.TagID 
AND tt.ThreadID = th.ThreadID 
AND ta.TagName in ('fedex', 'shipping')) = 2;