子查询
在嵌套查询中,最外面查询结果集返回给调用方,称为外部查询。嵌套在外部查询内的查询称为子查询,子查询的结果集供外部查询使用。
根据是否依赖外部查询,可将子查询分为自包含子查询和相关子查询。自包含子查询不依赖外部查询,相关子查询则依赖外部查询。
子查询结果是在运行时计算的,查询结果会跟随查询表的变化而改变。子查询可以返回单个值(标量)、多个值或者整个表结果。
在逻辑上,子查询代码仅在外部查询计算之前计算一次。
自包含子查询
USE WJChi; SELECT * FROM dbo.UserInfo WHERE Age= ( SELECT MAX(Age) FROM dbo.UserInfo );
相关子查询
USE WJChi; SELECT * FROM dbo.UserInfo AS UI WHERE IdentifyId = ( SELECT Id FROM dbo.Identify WHERE Id=UI.IdentifyId );
子查询易错点
NULL值处理不当
USE WJChi; SELECT * FROM dbo.Customers WHERE custid NOT IN( SELECT TOP 10 C.custid FROM dbo.Customers AS C ORDER BY C.custid );
上述查询语句看起来可以正常运行,但当子查询的返回结果集中包含NULL值时,上述查询语句则不会返回任何数据。解释如下:
20 NOT IN(10, 9, 8, NULL)等价于NOT(20=10 OR 20=9 OR 20=8 OR 20=NULL),NULL参与的比较预算结果均为Unknown,Unknown参与的或运算结果依然为Unknown。
⚠️ 我们应时刻牢记SQL是三值逻辑,这点很容易引发错误
列名处理不当
子查询中的列名首先从当前查询中进行解析,若未找到则到外部查询中查找。子查询中很有可能无意中包含了外部查询的列名导致子查询有自包含子查询变为相关子查询而引发逻辑错误。
为避免上述错误,查询中的列名尽可能使用完全限定名:[表名].[列名]。
⚠️ 通常我们自己难以发现代码中的逻辑错误,而我们的最终用户尝尝扮演着问题发现者的角色