如何在SQL查询的同一条WHERE子句中使用函数返回值进行过滤
解答
结论先行
- 你当前用的嵌套子查询外层过滤的方案是完全正确的,逻辑上不会有结果错误的问题。
- 不能直接在原查询的WHERE子句里引用
Commission别名,但可以通过调整实现同一层查询过滤。
具体说明
为什么不能直接在WHERE里用别名
SQL的逻辑执行顺序是:FROM/JOIN → WHERE → GROUP BY → HAVING → SELECT → ORDER BY,SELECT里定义的别名要到SELECT阶段才会生成,WHERE执行时还识别不到这个别名,直接写WHERE Commission >= @minCommission会直接报错。
同层查询的实现方式
因为你的查询用了GROUP BY分组,分组后的结果过滤应该用HAVING子句,不需要嵌套子查询也可以写:
select e.EmployeeId, e.EmpName, d.DepartmentId ,SUM(dbo.GetEmployeeCommissionByTransactionId(t.id)) Commission -- 注意要加聚合函数,原写法不加聚合在高版本SQL Server会报错 from Employees e inner join Department d on e.DepartmentId = d.Id left join [Transaction] t on t.EmployeeId = e.Id where d.DepartmentId in (@departmentIds) --other filters group by e.EmployeeId, e.EmpName, d.DepartmentId having SUM(dbo.GetEmployeeCommissionByTransactionId(t.id)) >= @minCommission and SUM(dbo.GetEmployeeCommissionByTransactionId(t.id)) <= @maxCommission;
注意:你原查询里
DISTINCT和GROUP BY同时使用是多余的,GROUP BY已经按员工维度去重了,可以删掉DISTINCT。另外因为你左连了交易表,一个员工可能对应多笔交易,所以佣金计算必须加聚合函数(比如SUM/MAX,根据你的业务需求选择),否则分组后不知道返回哪笔交易的佣金,高版本SQL Server会直接报语法错误。
效率对比
- 嵌套子查询和直接写在
HAVING里的执行效率几乎没有差异,数据库优化器会自动识别等价逻辑,生成一样的执行计划。 - 如果你用的是标量自定义函数,两种写法都会存在逐行调用的性能开销,如果数据量较大,建议把函数逻辑拆解成JOIN操作,或者改成内联表值函数调用,能大幅提升执行效率。
逻辑注意事项
不要直接把函数条件写在WHERE子句里:因为你用的是LEFT JOIN交易表,没有交易的员工t.id为NULL,函数返回NULL,写在WHERE里会直接过滤掉没有交易的员工,相当于把LEFT JOIN变成了INNER JOIN,不符合原有逻辑。
内容的提问来源于stack exchange,提问作者I Love Stackoverflow
相关产品推荐
相关产品推荐

