SQL Server中计算列Distance在WHERE子句报错‘无效列名’的原因
问题原因分析
这是SQL里非常常见的执行顺序陷阱!你遇到的问题核心在于:SQL语句的逻辑执行顺序和代码书写顺序完全不一样。
当数据库执行你的查询时,它会按这个流程走:
- 先执行
FROM [tblAddress],定位要操作的表 - 接着执行
WHERE DeletedOn IS NULL AND Distance <= @iRadius,筛选符合条件的行 - 最后才会执行
SELECT子句,计算Distance和PriorityType这些字段
换句话说,在执行WHERE子句的时候,SELECT里定义的Distance别名还根本没生成呢!数据库不知道你说的Distance是什么,自然就抛出“无效列名”的错误了。
解决方案
有几种简单的方式能解决这个问题,我结合你的查询逐一说明:
方案1:使用CTE(公共表表达式,推荐)
把计算Distance的逻辑放到CTE里,后续查询就能直接引用这个别名,代码可读性也更强:
Declare @mPoint As varchar(50) = 'POINT (-107.657141 41.033581)' Declare @iRadius As int = 5000 --5km for testing. 4 results, 1 with PriorityType = 0. WITH AddressWithDistance AS ( SELECT FLOOR([Position].STDistance(geography::STGeomFromText(@mPoint, 4326))) AS Distance, CASE WHEN [Type] & 64 = 64 THEN 0 ELSE 1000 END AS PriorityType, * FROM [tblAddress] WHERE DeletedOn IS NULL ) SELECT * FROM AddressWithDistance WHERE Distance <= @iRadius ORDER BY PriorityType ASC, Distance ASC;
方案2:使用子查询
和CTE原理类似,把计算逻辑放到子查询中,外层查询再做筛选:
Declare @mPoint As varchar(50) = 'POINT (-107.657141 41.033581)' Declare @iRadius As int = 5000 --5km for testing. 4 results, 1 with PriorityType = 0. SELECT * FROM ( SELECT FLOOR([Position].STDistance(geography::STGeomFromText(@mPoint, 4326))) AS Distance, CASE WHEN [Type] & 64 = 64 THEN 0 ELSE 1000 END AS PriorityType, * FROM [tblAddress] WHERE DeletedOn IS NULL ) AS TempTable WHERE Distance <= @iRadius ORDER BY PriorityType ASC, Distance ASC;
方案3:重复计算表达式(不推荐)
你也可以直接在WHERE子句里重复写FLOOR([Position].STDistance(...)),但这种方式缺点很明显:后续修改计算逻辑时,得同时改SELECT和WHERE两处,维护成本高,而且数据库可能会重复计算这个表达式(虽然SQL Server有时会优化,但不建议依赖这点):
Declare @mPoint As varchar(50) = 'POINT (-107.657141 41.033581)' Declare @iRadius As int = 5000 --5km for testing. 4 results, 1 with PriorityType = 0. SELECT FLOOR([Position].STDistance(geography::STGeomFromText(@mPoint, 4326))) AS Distance, CASE WHEN [Type] & 64 = 64 THEN 0 --insert other types as needed. ELSE 1000 END AS PriorityType, * FROM [tblAddress] WHERE DeletedOn IS NULL AND FLOOR([Position].STDistance(geography::STGeomFromText(@mPoint, 4326))) <= @iRadius ORDER BY PriorityType ASC, Distance ASC;
额外提示
顺便提一句,ORDER BY子句是可以直接用SELECT里的别名的,因为它是最后执行的步骤,这也是为什么你注释掉WHERE行后,排序能正常工作的原因。
内容的提问来源于stack exchange,提问作者Diamundo
相关产品推荐
相关产品推荐

