WHERE 语句中的 SQL Server AS 语句别名列

Posted

技术标签:

【中文标题】WHERE 语句中的 SQL Server AS 语句别名列【英文标题】:SQL Server AS statement aliased column within WHERE statement 【发布时间】:2010-06-22 19:06:02 【问题描述】:

我想执行一个查询,在该查询中我使用“AS”语句重命名列之一,并在“WHERE”语句中重用该别名列名。下面是一个例子:

SELECT lat AS latitude 
FROM poi_table 
WHERE latitude < 500

这里的问题是 SQL Server 不喜欢这个查询,因为 WHERE 子句和 WHERE 子句中引用了 AS 语句名称。谁能解释为什么会发生这种情况以及我可以做些什么来纠正我的情况?

假设我有一个公式,我在查询的 SELECT 部分中使用了别名,我该如何解决?

SELECT *, 
( 6371*1000 * acos( cos( radians(42.3936868308) ) * cos( radians( lat ) ) * cos( radians( lon ) - radians(-72.5277256966) ) + sin( radians(42.3936868308) ) * sin( radians( lat ) ) ) ) 
AS distance
FROM poi_table 
WHERE distance < 500;

【问题讨论】:

【参考方案1】:

SQL 通常不允许您在 WHERE、GROUP BY 或 HAVING 子句中引用列别名。 mysql 确实支持在 GROUP BY 和 HAVING 中引用列别名,但我强调当将此类查询移植到其他数据库时会出现问题。

如有疑问,请使用实际的列名:

SELECT t.lat AS latitude 
  FROM poi_table t
 WHERE t.lat < 500

我添加了一个表别名,以便更轻松地查看实际列与别名。

更新


一个计算列,就像您在此处看到的那样:

SELECT *, 
       ( 6371*1000 * acos( cos( radians(42.3936868308) ) * cos( radians( lat ) ) * cos( radians( lon ) - radians(-72.5277256966) ) + sin( radians(42.3936868308) ) * sin( radians( lat ) ) ) ) AS distance
  FROM poi_table 
 WHERE distance < 500;

...不会改变您不能在 WHERE 子句中引用列别名。要使该查询起作用,您必须使用:

SELECT *, 
       ( 6371*1000 * acos( cos( radians(42.3936868308) ) * cos( radians( lat ) ) * cos( radians( lon ) - radians(-72.5277256966) ) + sin( radians(42.3936868308) ) * sin( radians( lat ) ) ) ) AS distance
  FROM poi_table
 WHERE ( 6371*1000 * acos( cos( radians(42.3936868308) ) * cos( radians( lat ) ) * cos( radians( lon ) - radians(-72.5277256966) ) + sin( radians(42.3936868308) ) * sin( radians( lat ) ) ) ) < 500;

请注意,在列上使用函数(即:RADIANS(lat))将导致索引无用,如果列上存在索引。

【讨论】:

我添加了另一个(稍微复杂的)示例。您为表起别名的方法仍然有效吗?如果没有,那我需要做什么? @rohanbk:根据更新的更新问题示例更新答案。【参考方案2】:

SQL Server 已调整为在应用别名之前应用过滤器(因为这通常会产生更快的结果)。 你可以做一个嵌套的选择语句。示例:

SELECT Latitude FROM 
(
    SELECT Lat AS Latitude FROM poi_table
) A
WHERE Latitude < 500

我知道这可能不是您想要的,因为它会使您的查询更加冗长。 更简洁的方法是制作一个包装基础表的视图:

CREATE VIEW vPoi_Table AS 
SELECT Lat AS Latitude FROM poi_table

那么你可以说:

SELECT Latitude FROM vPoi_Table WHERE Latitude < 500

【讨论】:

如果您真的觉得需要重命名该列,也可以使用sp_rename。【参考方案3】:

我不知道为什么不能使用“lat”,但是如果必须的话,你可以重命名派生表中的列。

select latitude from (SELECT lat AS latitude FROM poi_table) p where latitude < 500

【讨论】:

【参考方案4】:

这将适用于您编辑的问题!

SELECT * FROM (SELECT <Column_List>,  
( 6371*1000 * acos( cos( radians(42.3936868308) ) * cos( radians( lat ) ) * cos( radians( lon ) - radians(-72.5277256966) ) + sin( radians(42.3936868308) ) * sin( radians( lat ) ) ) )  
AS distance 
FROM poi_table) TMP
WHERE distance < 500; 

【讨论】:

【参考方案5】:

SELECT语句的逻辑处理顺序

以下步骤显示了逻辑处理顺序或绑定 顺序,用于 SELECT 语句。此顺序确定对象何时 在一个步骤中定义的子句可用于后续的子句 脚步。例如,如果查询处理器可以绑定到(访问) FROM 子句中定义的表或视图,这些对象及其 列可用于所有后续步骤。反过来, 因为 SELECT 子句是第 8 步,所以任何列别名或派生 该子句中定义的列不能被前面引用 条款。但是,它们可以被后续子句引用,例如 ORDER BY 子句。请注意,实际的物理执行 语句由查询处理器确定,顺序可能会有所不同 从这个列表中。

    来自 开启 加入 在哪里 分组依据 使用多维数据集或使用汇总 有 选择 不同 订购人 顶部

来源:http://msdn.microsoft.com/en-us/library/ms189499%28v=sql.110%29.aspx

【讨论】:

【参考方案6】:

accepted answer 和 Logical Processing Order 都解释了为什么你不能按照你的建议去做。

可能的解决方案:

使用派生表(cte/子查询) 在WHERE中使用表达式 创建视图/计算列

SQL Server 2008,您可以使用APPLY 运算符与Table valued Constructor 结合使用:

SELECT *, s.distance
FROM poi_table 
CROSS APPLY (VALUES(6371*1000*acos(cos(radians(42.3936868308))*cos(radians(lat))*cos(radians(lon)-radians(-72.5277256966))+sin(radians(42.3936868308))*sin(radians(lat))))) AS s(distance)
WHERE distance < 500;

LiveDemo

【讨论】:

【参考方案7】:

我不知道为什么不能使用“lat”,但如果必须的话,你可以重命名派生表中的列。

select a.latitude from (SELECT lat AS latitude FROM poi_table) a where latitude < 500

【讨论】:

以上是关于WHERE 语句中的 SQL Server AS 语句别名列的主要内容,如果未能解决你的问题,请参考以下文章

where 子句中的 case 语句 - SQL Server

SQL Server:性能问题:WHERE 子句中的 OR 语句替换

简述SELECT语句中的FROM、WHERE以及ORDER BY子句的作用。SQL Server

sql server 2008 r2:当前会计年度 where 子句中的 case 语句

sql server中,修改视图名字的SQL语句

Sql Server:比较where子句中的varchar类型值不返回结果