选择与输入完全匹配的多对多行

时间:2017-10-06 01:00:28

标签: sql sql-server

使用3个表(Thread,Tag,ThreadTag),我正在尝试选择包含查询中提供的所有标记的线程。在这个例子中,我需要有'fedex'和'shipping'标签的线程,所以预期的结果是2行:ThreadIDs 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)

输出:

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

有效,但必须有更好的方法。

2 个答案:

答案 0 :(得分: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;

答案 1 :(得分: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;