【问题标题】:1 to Many Query: Help Filtering Results1对多查询:帮助过滤结果
【发布时间】:2026-02-20 20:05:01
【问题描述】:

问题:SQL 查询查看“多”关系中的值,但不返回“1”关系中的值。

表格示例:(这显示了两个不同的表格)。

+---------------+----------------------------+-------+
| Unique Number | <-- Table 1 -- Table 2 --> | Roles |
+---------------+----------------------------+-------+
|             1 |                            | A     |
|             2 |                            | B     |
|             3 |                            | C     |
|             4 |                            | D     |
|             5 |                            |       |
|             6 |                            |       |
|             7 |                            |       |
|             8 |                            |       |
|             9 |                            |       |
|            10 |                            |       |
+---------------+----------------------------+-------+

当我运行查询时,我会得到多个唯一的数字,这些数字显示了与每个数字相关联的所有角色,就像这样。

+---------------+-------+
| Unique Number | Roles |
+---------------+-------+
|             1 | C     |
|             1 | D     |
|             2 | A     |
|             2 | B     |
|             3 | A     |
|             3 | B     |
|             4 | C     |
|             4 | A     |
|             5 | B     |
|             5 | C     |
|             5 | D     |
|             6 | D     |
|             6 | A     |
+---------------+-------+

我希望能够运行我的查询并能够说,“当 A 的角色出现时,甚至不要向我显示具有 A 角色的唯一数字”。

如果 SQL 可以查看角色并说,当角色 A 出现时,获取唯一编号并将其从第 1 列中删除。

根据我“希望”发生的事情(我把它放在引号中,因为这可能甚至不可能)以下是我希望我的查询返回的内容。

+---------------+-------+
| Unique Number | Roles |
+---------------+-------+
|             1 | C     |
|             1 | D     |
|             5 | B     |
|             5 | C     |
|             5 | D     |
+---------------+-------+

更新:

查询示例:我正在查询 8 个表,但为了简单起见,我将其压缩为 4 个。

SELECT
c.UniqueNumber,
cp.pType,
p.pRole,
a.aRole

FROM c

JOIN cp ON cp.uniqueVal = c.uniqueVal
JOIN p  ON p.uniqueVal = cp.uniqueVal
LEFT OUTER JOIN a.uniqueVal = p.uniqueVal

WHERE
--I do some basic filtering to get to the relevant clients data but nothing more than that.

ORDER BY
c.uniqueNumber

表格大小:这些表格的行数可以从 50,000 到 500,000+

【问题讨论】:

  • 请包含您正在使用的查询。
  • 当然,我必须使它适合公众,因为这是针对客户的。

标签: sql sql-server ssms


【解决方案1】:

假装表名是t,列名是alphanumb

SELECT t.numb, t.alpha 
FROM t 
LEFT JOIN t AS s ON t.numb = s.numb 
      AND s.alpha = 'A' 
WHERE s.numb IS NULL;

你也可以做一个子选择:

SELECT numb, alpha 
FROM t 
WHERE numb NOT IN (SELECT numb FROM t WHERE alpha = 'A');

如果子选择不止一次实现,则选择以下之一(选择更快的那个,即具有较小子表大小的那个):

SELECT t.numb, t.alpha 
FROM t 
JOIN (SELECT numb FROM t GROUP BY numb HAVING SUM(alpha = 'A') = 0) AS s USING (numb);

SELECT t.numb, t.alpha 
FROM t 
LEFT JOIN (SELECT numb FROM t GROUP BY numb HAVING SUM(alpha = 'A') > 0) AS s USING (numb) 
WHERE s.numb IS NULL;

但第一个可能更快更好[1]。这些方法中的任何一种都可以合并到一个更大的查询中,并加入多个额外的表。

[1] 与涉及子选择的查询相比,直接连接往往更易于阅读且执行速度更快,而且自引用连接的常见异常非常罕见,因为它们需要表大小有很大的不匹配。但是,如果引用“A”alpha 值的行数非常少并且索引正确,那么您可能会遇到这些异常。

【讨论】:

  • 我既不同意也不反对“第一个可能更快更好”的断言,但是您做出该断言的基础将是对这个答案的适当补充。
【解决方案2】:

有很多方法可以做到这一点,权衡取舍取决于所涉及的表的大小和可用的索引等因素。在一般原则上,我的第一直觉是避免使用相关子查询,例如另一个现在已删除的答案,但如果关系表很小,那么它可能无关紧要。

此版本改为在where 子句中使用un相关子查询,并结合not in 运算符:

select num, role
from one_to_many
where num not in (select otm2.num from one_to_many otm2 where otm2.role = 'A')

如果one_to_many 中有很多行,这种形式可能特别有效,但只有一小部分具有角色A。当然,如果返回结果行的顺序很重要,您可以添加 order by 子句。

还有一些替代方法涉及加入内联视图或 CTE,其中一些可能在特定情况下具有优势。

【讨论】:

  • 约翰,谢谢你的回答。我在 WHERE 语句中尝试了 NOT IN 选择器,但它似乎删除了具有该角色的查询行,但唯一值仍然与其他角色一起弹出。然后那个领域几乎被隐藏了。这一切都与尝试测试信息有关,我需要的信息是唯一编号,但如果它们具有某些角色,我不能使用所有唯一编号。哈哈。
  • @BenDains,我不知道您尝试了什么,但我提出的查询产生的结果正是您所说的您想要的数据。这是a fiddle the demonstrates it
  • 谢谢约翰,我明天再试一下 NOT IN 子句,以确保我没有在此过程中搞砸。