sql - 过滤具有一对多关系的两个表之间的数据

标签 sql sql-server

Client表:

<表类=“s-表”> <标题> [CID] [名称] [年龄] <正文> 1 ABC 12 2 ACC 15 3 BBB 12

Status表:

<表类=“s-表”> <标题> [SID] [CID] [状态] <正文> 1 1 活跃 2 1 不活跃 3 1 未知 4 2 活跃 5 3 活跃 6 3 未知

客户端表已连接到 [CID] 上的状态表。我想要未将任何状态设置为“不活动”的客户的 [CID]。

这是我的尝试:

SELECT 
    A.[CID], B.[Status] 
FROM
    [Client table] AS A
INNER JOIN 
    [Status table] B ON A.[CID] = B.[CID]
WHERE 
    B.[Status] = 'Not Active' 

在这种情况下,它应该显示具有 CID 2 和 3 的客户端,而不显示具有 CID 1 的客户端。但是,当输入“状态 = 不活动”条件时,我得到了所有 CID 1、2 和 3。通过上述查询,我​​获得了所有三个 CID。

如何改进查询以仅显示 CID 2 和 3?我在这里做错了什么?

最佳答案

NOT EXISTS 是执行此操作的最有效方法。

不幸的是,SQL Server 要求子查询中至少有一列,因此您可以只执行 SELECT 1SELECT NULL。无论您做什么都会被忽略,它只是在子查询中查找行是否存在。请注意内部 WHERE 中与外部查询的相关性。

SELECT
  c.CID
FROM Client c
WHERE NOT EXISTS (SELECT 1
    FROM Status s
    WHERE s.CID = c.CID   -- correlation
      AND s.Status = 'Not Active'
);

如果您确实想使用联接查看所有 Status 行,那么窗口函数可能是最佳选择。

这里我们使用一个窗口函数,它可以一次计算多行,同时仍然返回所有行而不是聚合。 PARTITION BY 的工作方式与这里的 GROUP BY 类似,而 CASE WHEN 使其成为条件,因此它只计算与条件匹配的行。

SELECT
  c.CID
FROM Client c
JOIN (
    SELECT s.*,
      countNotActive = COUNT(CASE WHEN s.Status = 'Not Active' THEN 1 END) OVER (PARTITION BY s.CID)
    FROM Status s
) s ON s.CID = c.CID
WHERE s.countNotActive = 0;

关于sql - 过滤具有一对多关系的两个表之间的数据,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/76274963/

相关文章:

sql - MS SQL 拉丁字母排序规则中的阿拉伯字母

sql-server - SQL Server 中高效的字符串后缀搜索?

php - OOPHP 在函数内调用函数

sql - 关闭游标 - SQL 最佳实践

sql - SnowFlake MERGE 更新/插入所有列

sql-server - 是否可以在不关闭并重新打开的情况下刷新 "Show Table Data"的内容?

c# - 如何在 Entity Framework 投影中有效地获取远距离关系

sql - 从 SQL Server 2008 生成 XML 文件

php - 来自同一 ID 的 SQL 列的 SUM 值

sql-server - 如何使用 jooq 代码生成器和 maven 生成代码