PostgreSQL使用EXCEPT/NOT IN查询仅贷款无账户客户的SQL问题
问题背景
需求为在PostgreSQL中查询仅办理了贷款、未开设任何存款账户的客户ID(cust_ID)与客户姓名(customer_name),涉及核心表逻辑如下:
borrower表:存储贷款客户关联关系,包含cust_ID字段customer表:存储客户基础信息,包含cust_ID、customer_name字段depositor表:存储存款账户客户关联关系,包含cust_ID、account_number字段
原有写法错误分析
1. EXCEPT写法错误
EXCEPT 语法要求前后两个查询返回的列数量、列顺序、对应列数据类型完全一致,原写法第二个查询返回cust_ID、account_number两列,和第一个查询返回的cust_ID、customer_name列无法匹配,比较逻辑完全错位,因此返回结果不符合预期。
原错误代码:
(SELECT DISTINCT borrower.cust_ID, customer_name FROM borrower, customer where borrower.cust_ID = customer.cust_ID) except (SELECT DISTINCT cust_ID, account_number FROM depositor)
2. NOT IN写法错误
原写法将表关联条件borrower.cust_ID = customer.cust_ID放在NOT IN左侧,该等式返回的是布尔类型的判断结果,而右侧子查询返回的是字符类型的cust_ID,两边数据类型不匹配,直接抛出运算符不存在的错误。
原错误代码:
SELECT DISTINCT borrower.cust_ID, customer_name FROM borrower, customer WHERE (borrower.cust_ID = customer.cust_ID) NOT IN (SELECT cust_ID FROM depositor)
正确查询写法
以下三种写法均可得到预期的3条符合条件的客户结果:
写法1:修正后的EXCEPT写法
对齐前后两个查询的列结构,第二个查询第二列用NULL占位,和第一个查询的customer_name列匹配:
SELECT DISTINCT b.cust_ID, c.customer_name FROM borrower b INNER JOIN customer c ON b.cust_ID = c.cust_ID EXCEPT SELECT DISTINCT d.cust_ID, NULL FROM depositor d;
写法2:NOT EXISTS写法(推荐,性能最优)
直接判断有贷款记录的客户不存在对应的存款账户记录,无需处理列对齐问题,也不会触发NOT IN的空值异常:
SELECT DISTINCT b.cust_ID, c.customer_name FROM borrower b INNER JOIN customer c ON b.cust_ID = c.cust_ID WHERE NOT EXISTS ( SELECT 1 FROM depositor d WHERE d.cust_ID = b.cust_ID );
写法3:修正后的NOT IN写法
NOT IN 左侧仅放置需要判断的cust_ID字段,同时排除子查询中的空值避免结果异常:
SELECT DISTINCT b.cust_ID, c.customer_name FROM borrower b INNER JOIN customer c ON b.cust_ID = c.cust_ID WHERE b.cust_ID NOT IN ( SELECT cust_ID FROM depositor WHERE cust_ID IS NOT NULL );
注意:使用
NOT IN语法时必须确保子查询返回的cust_ID字段无NULL值,否则整个查询会返回空结果。
内容的提问来源于stack exchange,提问作者MCly
相关产品推荐
相关产品推荐

