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

时间:2010-06-22 19:06:03

标签: sql sql-server tsql

我想执行一个查询,在该查询中,我使用'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;

7 个答案:

答案 0 :(得分:30)

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;

请注意,使用列上的函数(IE:RADIANS(lat))会使索引无效(如果列上存在索引)。

答案 1 :(得分:11)

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

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

答案 2 :(得分:6)

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

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

答案 3 :(得分:3)

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

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; 

答案 4 :(得分:3)

  

SELECT语句的逻辑处理顺序

     

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

     
      
  1. FROM
  2.   
  3. ON
  4.   
  5. JOIN
  6.   
  7. WHERE
  8.   
  9. GROUP BY
  10.   
  11. WITH CUBE或WITH ROLLUP
  12.   
  13. HAVING
  14.   
  15. 选择
  16.   
  17. DISTINCT
  18.   
  19. ORDER BY
  20.   
  21. TOP
  22.   

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

答案 5 :(得分:1)

accepted answerLogical Processing Order都解释了为什么你不能做你提出的建议。

可能的解决方案:

  • 使用派生表(cte / subquery)
  • 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

答案 6 :(得分:0)

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

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