SQL Select based on value from sub-query - sql

I'm trying to select a set of users based on the latitude and longitude of another user for whom I have the ID. I need to do a distance calculation in the SELECT statement of the query and am not sure how to access the latitude and longitude of the user that I'm searching against.
Here is my query so far (which doesn't work)
SELECT
*,
(SELECT u1.latitude, u1.longitude
FROM user u1
WHERE u1.id = '77c3d4e0-37f6-4fae-b8ac-66cffad07179'),
(3959 * acos(cos(radians(u1.latitude))
* cos(radians(latitude))
* cos(radians(longitude) - radians(u1.longitude))
+ sin (radians(u1.latitude))
* sin(radians(latitude)))) AS distance
FROM
user u2
Basically I want to get all of the columns from user and a column called distance, which is the distance from the user with the ID

Move the subquery reference to the from clause:
SELECT u2.*,
(3959 * acos (
cos ( radians(u1.latitude) )
* cos( radians( u2.latitude ) )
* cos( radians( u2.longitude ) - radians(u1.longitude) )
+ sin ( radians(u1.latitude) )
* sin( radians( u2.latitude ) )
)
) AS distance
FROM icebreaker_user u2 JOIN
icebreaker_user u1
ON u1.id = '77c3d4e0-37f6-4fae-b8ac-66cffad07179'

Related

Postgres Input out of range

I am trying to make a SQL statement that finds all the records that are within a certain radius of a given latitude and longitude. When running this query I get an
input is out of range error
on it. I have two datapoint that are in the table one is the latitude and the other is the longitude both a decimal values.
The query:
$events = Event::whereRaw("acos(sin(latitude * 0.0175) * sin(${lat} * 0.0175)
+ cos(${lat} * 0.0175) * cos(${lat} * 0.0175) *
cos((${lng} * 0.0175) - (longitude * 0.0175))
) * 3959 <= 35")->paginate(7);
select *
from events
where acos(sin(latitude * 0.0175) * sin(34.1321461 * 0.0175)
+ cos(34.1321461 * 0.0175) * cos(34.1321461 * 0.0175) *
cos((-90.0594395 * 0.0175) - (longitude * 0.0175))
) * 3959 <= 35
I had no problem running this on MySQL database that I have also been working on for another project. Not sure what is going on here.
This query should return all the events within a certain radius in this case a 35 mile of the given lat and long.

Query Error with Having Clause using computed column

I am trying to find nearest locations based on latitude and longitude by using the locations in my database.
Here is my query:
select *,
acos(cos(33.7103820972222 * (PI()/180)) *
cos(73.05794 * (PI()/180)) *
cos(Lat * (PI()/180)) *
cos(Lon * (PI()/180))
+
cos(33.7103820972222 * (PI()/180)) *
sin(73.05794 * (PI()/180)) *
cos(Lat * (PI()/180)) *
sin(Lon * (PI()/180))
+
sin(33.7103820972222 * (PI()/180)) *
sin(73.05794 * (PI()/180))
) * 3959 AS Dist from tblOrg having Dist < 5 order by Dist
I am having error in Dist in the below line
having Dist < 5.
As marc_s commented "HAVING should only be used with conditions that include an aggregate function like SUM, COUNT etc. - otherwise, if you don't have any aggregate in your condition, use WHERE instead"
And you can't access a computed column directly in a having or where clause. So instead make a sub-query:
select *
from (
select *,
acos(cos(33.7103820972222 * (PI()/180)) *
cos(73.05794 * (PI()/180)) *
cos(Lat * (PI()/180)) *
cos(Lon * (PI()/180))
+
cos(33.7103820972222 * (PI()/180)) *
sin(73.05794 * (PI()/180)) *
cos(Lat * (PI()/180)) *
sin(Lon * (PI()/180))
+
sin(33.7103820972222 * (PI()/180)) *
sin(73.05794 * (PI()/180))
) * 3959 AS Dist
from tblOrg
) x
where Dist < 5
order by Dist
This query finally solved my issues.
tblOrg.Id as Id,
( 6371 * acos( cos( radians(33.7103820972222) )
* cos( radians( Lat ) )
* cos( radians( Lon )
- radians(73.05794) )
+ sin( radians(33.7103820972222) )
* sin( radians( Lat ) ) ) ) AS Distance
FROM
tblOrg
) AS P
WHERE
P.Distance< 5
ORDER BY
P.Distance;

Operand should contain 1 column(s) WHERE IN HAVING

I have a query where I am testing an 'IN' against a select.
I am getting an "Operand should contain 1 column(s)" error which I assume is because I am selecting more than 1 column in my 'IN' Select. I need the second column as part of my selector because I need to check it against a 'having' statement.
How can I make this work to get my desired effect?
SELECT DISTINCT c.ID, Title, URLSegment
FROM ListingCategory c
LEFT JOIN SiteTree_Live ON c.ID = SiteTree_Live.ID
JOIN ListingCategory_Listings lc
ON c.ID = lc.ListingCategoryID
WHERE lc.ListingID IN (
SELECT Listing.ID,
( 6371 * ACOS( COS( RADIANS(-45.0227996) ) * COS( RADIANS( Location.Latitude ) ) * COS( RADIANS( Location.Longitude ) - RADIANS(168.6991149) ) + SIN( RADIANS(-45.0227996) ) * SIN( RADIANS( Location.Latitude ) ) ) ) AS distance
FROM Listing
LEFT JOIN Location ON Listing.LocationID = Location.ID
having distance < 5
);
Easy - just don't select the calculated column. Also, it should be WHERE, not HAVING:
...
WHERE lc.ListingID IN (
SELECT Listing.ID
FROM Listing
LEFT JOIN Location ON Listing.LocationID = Location.ID
WHERE 6371 * ACOS( COS( RADIANS(-45.0227996) ) * COS( RADIANS( Location.Latitude ) ) * COS( RADIANS( Location.Longitude ) - RADIANS(168.6991149) ) + SIN( RADIANS(-45.0227996) ) * SIN( RADIANS( Location.Latitude ) ) )
< 5
);
What you you want to do cannot be done. An IN subquery must return a single column.
My suggestion is that you add table LINSTING to the join chain and then ask Listing.ID is not null.
Also: HAVING is for queries that have a GROUP BY clause.

Measuring distance between two Lat/Lng points

I am having issues trying to return the closest location to the user via an SQL statement. To test I am using the exact same coordinates, here is what I have:
SQL:
SELECT `companies`.`customerName` ,
(3959 *
ACOS(
COS(
RADIANS(37.367485) * COS(RADIANS(`locations`.`gps_lat`)) *
COS(
RADIANS(`locations`.`gps_lng`) - RADIANS(-77.399994) +
SIN(RADIANS(37.367485)) * SIN(RADIANS(`locations`.`gps_lat`))
)
)
)
)
AS `distance`
FROM `locations`
JOIN `companies` ON `locations`.`co_id`
HAVING `distance` > 25
ORDER BY distance
LIMIT 0 , 10
Results:
| customerName | distance |
| SOME COMPANY | 1914.41747964854 |
locations table values:
gps_lat | gps_lng
37.367485 | -77.399994
I used the example from Google, I checked the formula a couple times and I can't seem to come up with where I went wrong. Any help is appreciated.
EDIT:
Since there seems to be some confusion on me knowing what I am doing:
The > was substituted to yield a result, 1914 is obviously greater then 25.
The application of this is passing user coordinates from an Android app to our web server. The Latitude and Longitude will be pulled from the $_GET values and cross-referenced from companies in our web servers MYSQL database.
The syntax above is just me checking my SQL statement in Mysql Workbench. Obviously I am looking for a zero value result.
I think I have solved this issue by changing from Googles example to the formula provided by "Adventures of an adopted yooper". Using his/her version of the Haversine Formula.
Note: The Google example above is using Haversine as well.
SQL:
SELECT `companies`.`customerName` ,
(2 * (3959 * ATAN2(
SQRT(
POWER(SIN((RADIANS(37.367485 - `locations`.`gps_lat` ) ) / 2 ), 2 ) +
COS(RADIANS(`locations`.`gps_lat`)) *
COS(RADIANS(37.367485 )) *
POWER(SIN((RADIANS(-77.399994 - `locations`.`gps_lng` ) ) / 2 ), 2 )
),
SQRT(1-(
POWER(SIN((RADIANS(37.367485 - `locations`.`gps_lat` ) ) / 2 ), 2 ) +
COS(RADIANS(`locations`.`gps_lat`)) *
COS(RADIANS(37.367485)) *
POWER(SIN((RADIANS(-77.399994 - `locations`.`gps_lng` ) ) / 2 ), 2 )
))
)
))
AS 'distance'
FROM `locations`
JOIN `companies` ON `locations`.`co_id`
HAVING distance < 25
ORDER BY distance
LIMIT 0 , 10
For those curious on my application, Final PHP:
GET Value: ?lat=37.367485&lng=-77.399994
$earth_radius_miles = 3959; // Earth radius in miles
$earth_radius_kilometers = 6371; // Earth radius in kilometers
$result_radius = 10000; // Maximum distance in either miles or kilometers
$get_lat = $_GET["lat"];
$get_lng = $_GET["lng"];
$dbSelect = mysql_query("SELECT `companies`.`customerName`,
(2 * (".$earth_radius_miles." * ATAN2(
SQRT(
POWER(SIN((RADIANS(".$get_lat." - `locations`.`gps_lat` ) ) / 2 ), 2 ) +
COS(RADIANS(`locations`.`gps_lat`)) *
COS(RADIANS(".$get_lat.")) *
POWER(SIN((RADIANS(".$get_lng." - `locations`.`gps_lng` ) ) / 2 ), 2 )
),
SQRT(1-(
POWER(SIN((RADIANS(".$get_lat." - `locations`.`gps_lat` ) ) / 2 ), 2 ) +
COS(RADIANS(`locations`.`gps_lat`)) *
COS(RADIANS(".$get_lat.")) *
POWER(SIN((RADIANS(".$get_lng." - `locations`.`gps_lng` ) ) / 2 ), 2 )
))
)
))
AS 'distance'
FROM `locations`
JOIN `companies` ON `locations`.`co_id`
HAVING distance < ".$result_radius."
ORDER BY distance
LIMIT 0 , 10")
or die(mysql_error());
Results:
[{"customerName":"SOME COMPANY","distance":"0"}]
I have tested these results with other coordinates and seems to be working perfectly. Haven't tested anything with great distance between the two points but my application doesn't require me to do so.
Ashok, you can calculate the distance between two cordinates by using the below formula:
where
R = radius of the earth (6,371 km)
Δlat = |lat2- lat1|
Δlong = |long2- long1|

Query with HAVING and WHERE

I'm trying to create a single query that will combine the following two queries.
SELECT
campgroundid,
( 3959 * acos( cos( radians(37) ) * cos( radians( lat ) ) *
cos( radians( lng ) - radians(-122) ) +
sin( radians(37) ) * sin( radians( lat ) ) ) )
AS distance
FROM campground
HAVING distance < 25
ORDER BY distance LIMIT 0 , 20;
SELECT * FROM campground WHERE type='private' AND wifi = 1
I tried putting them into an IN but it returned a syntax error I couldn't figure out how to fix. I tried just removing the HAVING and combining the queries, but then it says it isn't able to figure out what distance is. Any help is appreciated. Thanks.
OUTPUT: [campgroundid, name, type,
wifi, distance] [1,camp ABC, private,
1, 1.34 mi] [2,camp XYZ, private, 1,
4.44 mi]
Among the information not given is how the campground and markers tables are related. We'll need that info to know how to JOIN the tables.
Also, HAVING requires GROUP BY (it operates like a WHERE clause on the aggregated results of GROUP BY). If you're not aggregating the rows in markers, you want WHERE, not HAVING.
At a guess, you want something like this:
SELECT id (expression) as distance FROM markers
WHERE distance < 25 AND
campground_id IN (SELECT id FROM campgrounds WHERE type = 'private' AND wifi = 1)
EDIT: Reflecting the new info that there's only one table.
You cannot use column ALIASes in a WHERE clause. I'm guessing you know that, and also know that you can use them in HAVING, which is why you're trying to swap HAVING in place of WHERE. To do that, you'll have to rewrite as a GROUP BY query:
SELECT campgroundid, name, private, wifi,
( 3959 * acos( cos( radians(37) ) * cos( radians( lat ) ) *
cos( radians( lng ) - radians(-122) ) +
sin( radians(37) ) * sin( radians( lat ) ) ) )
AS distance
FROM campground
GROUP BY campgroundid
HAVING distance < 25 AND type='private' AND wifi = 1
ORDER BY distance LIMIT 0 , 20;
This will work as long as campgroundid is unique (since the other values will then come from the only record for this id).
It looks like it should be WHERE distance < 25, as HAVING is for queries such as HAVING MAX(distance) < 25 and other aggregate functions.
I guess this is worth to try (as simple as add the where clause from second sql into first)
SELECT
... AS distance
FROM campground
WHERE type='private' AND wifi = 1
HAVING distance < 25
ORDER BY distance LIMIT 0 , 20;
SELECT
campgroundid,
( 3959 * acos( cos( radians(37) ) * cos( radians( lat ) ) *
cos( radians( lng ) - radians(-122) ) +
sin( radians(37) ) * sin( radians( lat ) ) ) )
AS distance
FROM campground
WHERE type='private' AND wifi = 1
ORDER BY distance LIMIT 0 , 20
HAVING distance < 25
this may work
If your question is to have WHERE clause from two tables with a JOIN logic.
Then you must include that value in SELECT list.
For e.g,
SELECT USER.UserName, USER.UserId, LOC.id, LOC.lat, LOC.lon, ( 3959 * acos( cos( radians('123.1210022') ) * cos( radians( lat ) ) * cos( radians( lon ) - radians('21.200001') ) + sin( radians('123.1210022') ) * sin( radians( lat ) ) ) ) AS distance
FROM userlocation LOC, user USER
HAVING distance < '1' AND LOC.id = USER.UserId
ORDER BY distance
LIMIT 0 , 20
If you miss USER.UserId in Select list, you will not be able to LOC.id = USER.UserId in the WHERE clause.