TSQL-如何获取记录可满足条件,而不会排除其他条件

时间:2018-11-21 20:58:40

标签: sql sql-server tsql

这看起来很简单,但是我好几年都没有接触过SQL。当我回来时,完全不喜欢这个数学。假设我有3张桌子,如下所示:

表名:

|NameId| Name |
|------|------|
| 1    | John |
| 2    | Doe  |
| 3    | Brian|

表格标签:

|TagId| Tag     |
|-----|---------|
| 1   | Teacher |
| 2   | Engineer|
| 3   | Employee|

表名称标签:

|NameId|TagId|
|----  |-----|
|1     | 1   |
|2     | 2   |
|2     | 3   |
|3     | 3   |

我想通过标签找到所有名称以及相关标签。例如。查找带有标签Employee(TagId = 3)的名称。 我希望这样的结果:

|NameId|TagId|
|----  |-----|    
|2     | 2   |
|2     | 3   |
|3     | 3   |

如何在T-SQL脚本中实现?

我尝试使用下面的脚本,但是它总是排除记录1 | 1和2 | 2:

SELECT *
FROM NameTag    
WHERE TagId = 3

我没想到的结果:

|NameId|TagId|
|----  |-----|        
|2     | 3   |
|3     | 3   |

更新

好像有很多解决方案在下面评论为@ plax,@ SteveB或@picklerick以及其他一些指出的解决方案。我没有机会测试所有这些,但它们似乎为我工作。谢谢你们! (今天对我来说是早感恩节。)

那时,我自己也找到了解决方案,并在此处发布以供参考。另外,@ plax在下面指出。

我的解决方案:

--Get persons that have the tag.
WITH Person_CTE AS
(
    SELECT DISTINCT NameId 
    FROM NameTag
    WHERE TagId = 3
)
-- Looking other tags for the person.
SELECT * 
FROM NameTag nt
JOIN Person_CTE p ON nt.NameId = p.NameId

@plalx指出的另一种解决方案写得很清楚:

  1. 找到所有关联TagID为3的NameId。

    SELECT NameId
    FROM NameTag
    WHERE TagId = 3
    
  2. 找到在步骤1中找到的NameId的所有标签。

    SELECT NameId, TagId
    FROM NameTag
    WHERE NameId IN 
        (-- Solution from #1
         SELECT NameId
         FROM NameTag
         WHERE TagId = 3)
    

5 个答案:

答案 0 :(得分:2)

当您无法解决查询问题时,请先将其分解为可以解决的较小问题,然后将较小的解决方案合并在一起。

  1. 查找与NameId相关的TagId的所有3。例如

    SELECT NameId
    FROM NameTag
    WHERE TagId = 3
    
  2. 找到在步骤#1中找到的NameId的所有标签。

    SELECT NameId, TagId
    FROM NameTag
    WHERE NameId IN (
        -- Solution from #1
        SELECT NameId
        FROM NameTag
        WHERE TagId = 3
    ) 
    

如果您随后遇到性能问题,可以从那里开始尝试优化,但是查询的表现力对于可维护性也很重要。

答案 1 :(得分:1)

或者使用相关子查询而不是联接,就像换种猫一样。

SELECT
  *
FROM
  @NameTag AS nt
WHERE
  EXISTS
(
  SELECT
    1
  FROM
    @NameTag AS n
  WHERE
    n.TagId = 3
    AND n.NameId = nt.NameId
);

结果:

+--------+-------+
| NameId | TagId |
+--------+-------+
|      2 |     2 |
|      2 |     3 |
|      3 |     3 |
+--------+-------+

答案 2 :(得分:1)

Select * from nametag where nameid in(Select nameid from nametag where tagid=3 Group by nameid) 

答案 3 :(得分:0)

我认为这可能是您想要的。

DECLARE @NameTag TABLE (NameId int, TagId int)

INSERT INTO @NameTag SELECT 1, 1
INSERT INTO @NameTag SELECT 2, 2
INSERT INTO @NameTag SELECT 2, 3
INSERT INTO @NameTag SELECT 3, 3

SELECT a2.*
FROM @NameTag a1
    JOIN @NameTag a2 on a1.NameId = a2.NameId
WHERE a1.TagId = 3 ;

答案 4 :(得分:0)

您可以在没有join的情况下执行此操作:

select nt.*
from (select nt.*,
             sum(case when tagid = 3 then 1 else 0 end) over (partition by nameid) as cnt_3
      from nametag nt
     ) nt
where cnt_3 > 0;