Reputation: 2783
Why does this SQL not work?
The:
6371 * ACos( Cos(RADIANS(Latitude)) * Cos(RADIANS('50.017466977673905')) * Cos(RADIANS('24.69924272460935')
- RADIANS(Longitude)) + Sin(RADIANS(Latitude)) * Sin(RADIANS('50.017466977673905')) )
Clause just calculates the order from a search point.
Which I am aliasing (because it so longwinded) to Distance.
SELECT [Hotel Id],
latitude,
longitude,
establishmentname,
6371 * ACos( Cos(RADIANS(Latitude)) * Cos(RADIANS('50.017466977673905')) * Cos(RADIANS('24.69924272460935') - RADIANS(Longitude)) + Sin(RADIANS(Latitude)) * Sin(RADIANS('50.017466977673905')) ) AS Distance
FROM [dbo].[RPT_hotels]
WHERE distance < '30'
ORDER BY Distance
Here I replace the "Distance < 30" with the longwinded phrase and it works fine.
I can even ORDER BY the column alias and that works!!?
SELECT [Hotel Id],
latitude,
longitude,
establishmentname,
6371 * ACos( Cos(RADIANS(Latitude)) * Cos(RADIANS('50.017466977673905')) * Cos(RADIANS('24.69924272460935') - RADIANS(Longitude)) + Sin(RADIANS(Latitude)) * Sin(RADIANS('50.017466977673905')) ) AS Distance
FROM [dbo].[RPT_hotels]
WHERE 6371 * ACos( Cos(RADIANS(Latitude)) * Cos(RADIANS('50.017466977673905')) * Cos(RADIANS('24.69924272460935') - RADIANS(Longitude)) + Sin(RADIANS(Latitude)) * Sin(RADIANS('50.017466977673905')) ) < '30'
ORDER BY Distance
What am I doing wrong?
Upvotes: 1
Views: 1770
Reputation: 14077
This happens because of natural query processing order, which is the following:
FROM
ON
OUTER
WHERE
GROUP BY
CUBE
| ROLLUP
HAVING
SELECT
DISTINCT
ORDER BY
TOP
You're assigning your alias in SELECT
statement. As you can see WHERE
is processed before SELECT
and ORDER BY
comes after it. That's the reason. Now what are the workarounds:
CROSS APPLY
. This should beautify your code a bit and is recommended method.CROSS APPLY
will assign alias before WHERE
statement, making it usable in it.
SELECT [Hotel Id]
, latitude
, longitude
, establishmentname
, Distance
FROM [dbo].[RPT_hotels]
CROSS APPLY (
SELECT 6371 * ACos(Cos(RADIANS(Latitude)) * Cos(RADIANS('50.017466977673905')) * Cos(RADIANS('24.69924272460935') - RADIANS(Longitude)) + Sin(RADIANS(Latitude)) * Sin(RADIANS('50.017466977673905')))
) AS T(Distance)
WHERE distance < 30
ORDER BY Distance;
If you want to find out more. Please read this question: What is the order of execution for this SQL statement
Upvotes: 6
Reputation: 1723
OREDER BY
is the final section of query processing. WHERE
is far before that. For that reason you can not use aliases into the WHERE
clause, but can use them inside the ORDER BY
.
See this link for details about query processing order.
Upvotes: 0
Reputation: 46203
As to why you can't specify an alias in the WHERE
clause, this is due to the logical order of query processing: (http://tsql.solidq.com/books/insidetsql2008/Logical%20Query%20Processing%20Poster.pdf).
The WHERE
clause is processed after the SELECT
clause but ORDER BY
is processed afterward. Column aliases can only be referenced after the SELECT
clause has been processed.
Upvotes: 2
Reputation: 461
The WHERE clause is being processed before the SELECT clause and because of that you can't use any alias in the WHERE clause. The ORDER BY clause is being processed after the SELECT, so you can use aliases there.
Upvotes: 0
Reputation: 62
The ORDER BY clause is processed after the SELECT fields, in parsing. So, when it will order the clause, the alias are known but when it will filter by WHERE clause, they are not.
Try surrouding with another SELECT clause and move the WHERE and ORDER BY clauses to it.
SELECT * FROM (SELECT ...) WHERE ... ORDER BY ...
Upvotes: 0
Reputation: 16958
I suggest you to use an inner select like this:
SELECT *
FROM (
SELECT
[Hotel Id],latitude,longitude,establishmentname,6371 * ACos( Cos(RADIANS(Latitude)) * Cos(RADIANS('50.017466977673905')) * Cos(RADIANS('24.69924272460935') - RADIANS(Longitude)) + Sin(RADIANS(Latitude)) * Sin(RADIANS('50.017466977673905')) ) AS Distance
FROM
[dbo].[RPT_hotels] ) t
WHERE Distance < 30
ORDER BY Distance;
Note that ORDER BY
can use aliases and column number also.
Another way is using CTE
like this:
;WITH t AS (
SELECT
[Hotel Id],latitude,longitude,establishmentname,6371 * ACos( Cos(RADIANS(Latitude)) * Cos(RADIANS('50.017466977673905')) * Cos(RADIANS('24.69924272460935') - RADIANS(Longitude)) + Sin(RADIANS(Latitude)) * Sin(RADIANS('50.017466977673905')) ) AS Distance
FROM
[dbo].[RPT_hotels] )
SELECT *
FROM t
WHERE Distance < 30
ORDER BY Distance;
Upvotes: 0
Reputation: 13700
It is the way it works. Note that ORDER BY Clause is applied after generating the entire data so the engine knows the alias name but WHERE clause does not know it until you use a derived table
select * from
(
SELECT [Hotel Id],latitude,longitude,establishmentname,6371 *
ACos( Cos(RADIANS(Latitude)) * Cos(RADIANS('50.017466977673905')) *
Cos(RADIANS('24.69924272460935') - RADIANS(Longitude)) +
Sin(RADIANS(Latitude)) * Sin(RADIANS('50.017466977673905')) ) AS Distance
FROM [dbo].[RPT_hotels]
) as t
WHERE Distance < '30' ORDER BY Distance
Upvotes: 0