Use result of substring function to compute values for multiple columns
문제
I am trying to run to find the closest point with a long and lat. Which works fine is i have separate value stored in my db, however i have a single piped string, which i am able to split with a substring index. However when i try and combine these functions in my select query i am not getting any joy.
SELECT SUBSTRING_INDEX(SUBSTRING_INDEX(longlat, '|', 1), '|', -1) as 'lat',
SUBSTRING_INDEX(SUBSTRING_INDEX(longlat, '|', 2), '|', -1) as 'lng',
title,
( 6371 * acos( cos( radians(51.527351) ) * cos( radians( 'lat') ) * cos( radians( 'lng' ) - radians(0.765544) ) + sin( radians(51.527351) ) * sin( radians( 'lat' ) ) ) ) AS distance
FROM locations HAVING distance < 500
ORDER BY distance
LIMIT 0 , 20
Can anyone shed some light?
해결책
radians( 'lat')
In this part of the query, 'lat'
is a string, not a column name or similar. When passing that string to radians
, it will be converted to a number, in this case to zero. So you're converting 0 to radians.
You cannot use one column as the input to the computation of the value of another column. You either have to repeat the expression, or use a subquery like this:
SELECT lat, lng, title,
(6371 * acos(cos(radians(51.527351)) *
cos(radians(lat)) * cos(radians(lng) - radians(0.765544)) +
sin(radians(51.527351)) * sin(radians(lat)))
) AS distance
FROM
(SELECT title,
SUBSTRING_INDEX(SUBSTRING_INDEX(longlat, '|', 1), '|', -1) + 0 as lat,
SUBSTRING_INDEX(SUBSTRING_INDEX(longlat, '|', 2), '|', -1) + 0 as lng
FROM locations
) AS sub
HAVING distance < 500
ORDER BY distance
LIMIT 0 , 20
다른 팁
Here was my solution which repeats the query. I haven;t had a chance to test of benchmark the differing solutions, but the subquery solution is more pleasant
SELECT SUBSTRING_INDEX(SUBSTRING_INDEX(longlat, '|', 1), '|', -1) as 'latitude',
SUBSTRING_INDEX(SUBSTRING_INDEX(longlat, '|', 2), '|', -1) as 'longitude',
(
3959 * acos(
cos(radians({MYLAT})) * cos(radians(SUBSTRING_INDEX(SUBSTRING_INDEX(longlat, '|', 1), '|', -1)))
* cos(radians(SUBSTRING_INDEX(SUBSTRING_INDEX(longlat, '|', 2), '|', -1))) - radians({MYLONG}) + sin(radians({MYLAT}))
* sin( radians(SUBSTRING_INDEX(SUBSTRING_INDEX(longlat, '|', 1), '|', -1)))
)
)
AS distance,
title
FROM locations
ORDER BY distance
LIMIT 0 , 20
Turns out i'm going to be using this equation everywhere now, so glad to get it nailed :)
I'm using the averaged 3959 as the earth's radius, however i wonder if i might be better to use some kind regional latitude for different global locations.