TSQL-如何获取满足条件的记录,而不排除其他不满足条件的记录
这看起来很简单,但我已经多年没有接触过SQL了。当我回来的时候,我完全沉浸在数学中。假设我有3张表,如下所示: 表名:TSQL-如何获取满足条件的记录,而不排除其他不满足条件的记录,sql,sql-server,tsql,Sql,Sql Server,Tsql,这看起来很简单,但我已经多年没有接触过SQL了。当我回来的时候,我完全沉浸在数学中。假设我有3张表,如下所示: 表名: |NameId| Name | |------|------| | 1 | John | | 2 | Doe | | 3 | Brian| 表格标签: |TagId| Tag | |-----|---------| | 1 | Teacher | | 2 | Engineer| | 3 | Employee| 表名称标签: |Name
|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 |
--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
如何在T-SQL脚本中实现这一点
我尝试使用下面的脚本,但它总是排除记录1 | 1和2 | 2:
SELECT *
FROM NameTag
WHERE TagId = 3
结果我不期望:
|NameId|TagId|
|---- |-----|
|2 | 3 |
|3 | 3 |
更新 看起来有许多解决方案在下面被评论为@plax、@stevenb或@picklerick等。我还没有机会测试所有这些,但它们似乎对我有用。谢谢大家!!(对我来说,今天的感恩节很早) 到那时,我自己也找到了一个解决方案,并张贴在这里供参考。还有,@plax在下面指出 我的解决方案:
|NameId|TagId|
|---- |-----|
|2 | 2 |
|2 | 3 |
|3 | 3 |
--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指出的另一个解决方案写得非常清楚:
SELECT NameId
FROM NameTag
WHERE TagId = 3
我想这可能就是你要找的
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 ;
我想这可能就是你要找的
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 ;
或者使用相关子查询而不是联接,就像剥猫皮的另一种方法一样
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 |
+--------+-------+
或者使用相关子查询而不是联接,就像剥猫皮的另一种方法一样
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 |
+--------+-------+
当你不能解决一个查询问题时,首先把它分解成你能解决的小问题,然后把小问题合并在一起
3
的TagId
关联的NameId
。例如
SELECT NameId
FROM NameTag
WHERE TagId = 3
NameId
的所有标记
如果您随后遇到性能问题,您可以从那里开始并尝试优化,但查询的表达能力对于可维护性也很重要。当您无法解决查询问题时,首先将其分解为可以解决的较小问题,然后将较小的解决方案合并在一起
Select * from nametag where nameid in(Select nameid from nametag where tagid=3 Group by nameid)
3
的TagId
关联的NameId
。例如
SELECT NameId
FROM NameTag
WHERE TagId = 3
NameId
的所有标记
如果您随后遇到性能问题,您可以从那里开始并尝试优化,但查询的表达能力对于可维护性也很重要。您可以在不加入
的情况下执行此操作:
Select * from nametag where nameid in(Select nameid from nametag where tagid=3 Group by nameid)
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;
无需加入即可执行此操作:
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;
那么你想要一个结果集,其中包含一个标记的所有名称以及这些名称的所有标记?那么。。。你想要的结果是什么?@SteveB:是的,我想要。@JasonA.Long:我在帖子里说了。那么你想要一个包含所有标签名和所有标签名的结果集?那么。。。你想要的结果是什么?@SteveB:是的,我想要。@JasonA.Long:我在帖子中说过。在我回过头来看这个答案之前,我自己已经找到了解决方案。加上你如何描述解决问题。非常感谢!我也在上面发布了我的解决方案。太好了!我很高兴你找到了解决办法。在您的解决方案中,给定的(NameId,TagId)
对已经是唯一的,因此您不需要重复的NameId
,条件是其中TadId=3
。我在最初的回答中犯了同样的错误。实际上,表名标签有一个Id。我忘了把它包括在内。@thangguyen我不确定我是否理解你的评论和我的有什么关系?:Pit确实需要DISTINCT关键字,因为NameId和TagId不是唯一的。很抱歉没有提到:D.在我回顾这个答案之前,我自己已经找到了一个解决方案。加上你如何描述解决问题。非常感谢!我也在上面发布了我的解决方案。太好了!我很高兴你找到了解决办法。在您的解决方案中,给定的(NameId,TagId)
对已经是唯一的,因此您不需要重复的NameId
,条件是其中TadId=3
。我在最初的回答中犯了同样的错误。实际上,表名标签有一个Id。我忘了把它包括在内。@thangguyen我不确定我是否理解你的评论和我的有什么关系?:Pit确实需要DISTINCT关键字,因为NameId和TagId不是唯一的。很抱歉没有提到:D。尽管我还没有完全测试,但它看起来是一个非常聪明的解决方案。我会看看它。@ThangNguyen它之所以有效,是因为对特定单个TagId
的任何约束都保证返回唯一的NameId
sa1
将引用所有唯一的NameId
s,其中TagId=3
,JOIN
基本上充当我答案中的IN
子句。我更喜欢
中的子句,因为它更接近我们想要实现的语义。此外,如果初始条件更改为(2,3)
中的TagId,则解决方案将返回重复项。两个解决方案都应该有一个类似的执行计划,这也是一个好的计划。@plalx我同意IN是一个更容易阅读的解决方案,我喜欢它。如果内部查询的结果会变得相当大,我们只是试图避免它,因为我们已经看到了它的性能问题。如果可能的话,我们通常用EXISTS查询或JOIN替换它。我真的希望更容易阅读的查询版本总是最快的查询。在这个例子中,你是完全正确的,我应该包括它以及现有的版本。它看起来像一个非常聪明的解决方案,尽管我还没有完全测试。我会看看它。@ThangNguyen它之所以有效,是因为对特定单个TagId
的任何约束都保证返回唯一的NameId
s<代码>a1