如何使用SQL跨多表查询筛选不匹配指定条件的结果
多表关联地址校验的查询实现方案
判定规则前置明确
我们要筛选的不匹配结果,核心判定标准可以拆成两层:
- 覆盖范围:每个主用户本身,以及该用户通过Relationship表关联的所有亲属
- 不匹配触发条件:覆盖范围内的任意主体,不存在对应的有效地址记录
实现思路拆解
整个逻辑不需要复杂的嵌套,拆成三步就可以走完流程:
- 先把所有需要校验地址的主体拆成两类:用户本人、用户关联的亲属,合并成统一的待校验ID集合
- 把待校验ID集合和address表做左连接,标记每个ID是否存在有效地址
- 按主用户维度聚合,只要聚合结果里存在任意一个待校验ID无有效地址,就归为不匹配的结果,输出即可
可直接落地的参考SQL(兼容MySQL、PostgreSQL等主流关系型数据库)
采用分步CTE的写法可读性更高,后续加过滤规则也方便:
WITH check_scope AS ( -- 纳入校验范围:用户本人 SELECT id AS main_user_id, id AS person_id, '用户本人' AS relation_tag FROM Person -- 可按需加过滤,比如排除纯亲属建档、没有平台账号的记录 UNION ALL -- 纳入校验范围:用户的所有直接关联亲属 SELECT main_id AS main_user_id, related_id AS person_id, relation_type AS relation_tag FROM Relationship r INNER JOIN Person p ON r.related_id = p.id -- 确保关联的亲属记录有效 ), address_check_result AS ( -- 逐人匹配地址,标记是否存在有效地址 SELECT main_user_id, person_id, relation_tag, CASE WHEN a.id IS NOT NULL THEN 1 ELSE 0 END AS has_valid_addr FROM check_scope s LEFT JOIN address a ON s.person_id = a.user_id -- 按需加有效地址规则:比如未软删、状态为正常的地址 AND a.is_deleted = 0 AND a.status = 1 ) -- 最终输出不匹配的结果 SELECT main_user_id, p.name AS main_user_name, COUNT(CASE WHEN has_valid_addr = 0 THEN 1 END) AS missing_addr_count, GROUP_CONCAT( DISTINCT CONCAT(person_id, '(', relation_tag, ')') SEPARATOR '、' ) AS missing_addr_person FROM address_check_result r INNER JOIN Person p ON r.main_user_id = p.id GROUP BY main_user_id, p.name -- 核心筛选条件:存在至少1个校验对象没有有效地址 HAVING missing_addr_count > 0
高性能简化版本(不需要明细展示缺失对象时适用)
如果只需要快速捞出来不符合规则的主用户ID,不需要展示具体哪个人缺地址,可以用EXISTS写法,查询性能比聚合写法高很多,尤其适合表数据量较大的场景:
SELECT p.* FROM Person p WHERE -- 第一种缺失情况:用户本人没有有效地址 NOT EXISTS ( SELECT 1 FROM address a WHERE a.user_id = p.id AND a.is_deleted = 0 AND a.status = 1 ) -- 第二种缺失情况:任意一个关联亲属没有有效地址 OR EXISTS ( SELECT 1 FROM Relationship r LEFT JOIN address a ON r.related_id = a.user_id AND a.is_deleted = 0 AND a.status = 1 WHERE r.main_id = p.id AND a.id IS NULL )
常见踩坑提醒
- 关联address表时一定要用左连接,不要提前做内连接过滤,否则会把“没有地址的用户/亲属”直接从结果集里滤掉,导致计算逻辑完全错误
- 如果后续需要校验多层亲属关联(比如用户的祖父母、配偶的父母等),只需要在
check_scope里加递归CTE遍历关联关系树即可,整体逻辑不需要调整 - 关联关系表如果存的是双向关联(比如A是B的父亲,同时存了B指向A的关系),一定要去重,避免同一个人被重复计算,导致缺失统计数量不准
内容的提问来源于stack exchange,提问作者hitesh.gawhade
相关产品推荐
相关产品推荐

