Hibernate MySQL Haversine - mysql

I am attempting to use the Haversine formula. Ideally, I would like to use Hibernate provider with JPA and MySQL. This is the following query that I am using which appears to work in MySQL.
SELECT campusid, ( 3959 * acos( cos( radians(37) ) * cos( radians( latitude ) ) * cos( radians( longitude ) - radians(-122) ) + sin( radians(37) ) * sin( radians( latitude ) ) ) ) AS distance FROM mydb.campus HAVING distance < 25 ORDER BY distance LIMIT 0 , 20;
I am trying to see how I could use Hibernate and would like a cleaner way of doing this. I looked at the Criteria API but can't seem to find a way to execute this.

That query is unlikely to be possible in Hibernate and certainly not in a clean way. You can however execute a native SQL query.
session.createSQLQuery("your sql here");
This will tie you to MySQL but should work.

Related

SQL query to find closest distance between coordinates is running very slowly

I have the following query which does indeed work. It takes in a hard set Latitude and Longitude and finds the closest set of coordinates, along with it's postal code.
What I'm having trouble with is the speed of the query. It's currently taking 3.8 seconds to run and I have 9000 separate coordinates to check.
Any advice on how to speed this up would be greatly appreciated.
SELECT pcds, ROUND(MIN(distance), 4) AS distance FROM
(SELECT `postcode`.`pcds`,(
6371 * acos (
cos ( radians('51.4932392') )
* cos( radians( `postcode`.`lat` ) )
* cos( radians( `postcode`.`lng` ) - radians('-0.0846429') )
+ sin ( radians('51.4932392') )
* sin( radians( `postcode`.`lat` ) )
)
) AS distance
FROM postcode
ORDER BY distance
LIMIT 1
) AS First

Haversine formula on a Firebird database

I used the following sql for mySQL but I now need to use this for a Firebird database. I have searched and read the Firebird documentation but can't seem to locate an alternative. In Firebird 'radians' and 'limit' both are not supported. Has anyone successfully done similar in Firebird?
SELECT zip, ( 3959 * acos( cos( radians(38.6285426) ) * cos( radians( lat ) )
* cos( radians( lng ) - radians(-86.05296039999999) ) + sin( radians(38.6285426) ) * sin(radians(lat)) ) ) AS distance
FROM zipcodes
HAVING distance < 25
ORDER BY distance
LIMIT 0 , 20;
The radians function in mySQL "returns the argument X, converted from degrees to radians". You don't need builtin function to do that, it's rather simple math: radians = degrees × π / 180º. You could create an convenience view with calculated columns for deg-to-rad conversion, to make the query easier to read. BTW, Firebird has builtin function for retrieving π value.
Instead of LIMIT Firebird supports ROWS syntax:
SELECT <columns> FROM ...
[WHERE ...]
[ORDER BY ...]
ROWS <m> [TO <n>]
For anyone having a similar issue, here was my solution for Firebird that returns all zips codes within a certain mile radius of a Lat/long (Great Circle) in one query.
select zipcode from(
SELECT zipcode, ( 3959 * acos( cos( 38.6285426/57.2958 ) * cos( lat/57.2958 )
* cos( lon/57.2958 - -86.05296039999999/57.2958 ) + sin( 38.6285426/57.2958 ) * sin(lat/57.2958) ) ) AS distance
FROM zip_codes)
where distance < 20
ORDER BY distance

MySQL sub query with two columns - how to hide the second column?

I'm having a difficult time wrapping my head around how to do this, even with all the searching and reading I've done on this!
I have a query I am using to try to pull all users from a database that have a zip code that falls within a certain distance of a given decimal coordinate. Here's the query that I am running:
select distinct watch_list.username, enabled
from watch_list, registered_users
where watch_list.username = registered_users.username AND watch_list.watchzip = (
SELECT zip,
( 3959 * acos( cos( radians('29.7632800') ) *
cos( radians( lat ) ) *
cos( radians( lng ) -
radians('-95.3632700') ) +
sin( radians('29.7632800') ) *
sin( radians( lat ) ) ) )
AS distance from zip
HAVING distance <= '10');
There error I get back is expected, as my sub query is returning two columns:
MySQL said: Documentation
#1241 - Operand should contain 1 column(s)
How can I do this and filter on the distance without the sub query returning both columns?
P.S. Just for completion and information sake, the "zip" table contains a list of all zip codes in the U.S. along with their decimal coordinates.
Just move the operation out of the column list:
select distinct watch_list.username, enabled
from watch_list, registered_users
where watch_list.username = registered_users.username
AND watch_list.watchzip = (
SELECT zip
from zip
WHERE ( 3959 * acos( cos( radians('29.7632800') ) *
cos( radians( lat ) ) *
cos( radians( lng ) -
radians('-95.3632700') ) +
sin( radians('29.7632800') ) *
sin( radians( lat ) ) ) ) <= '10');
Edit: As P.Salmon mentions, you probably also want to change AND watch_list.watchzip = to AND watch_list.watchzip IN.

Combining multiple where conditions in mysql SELECT query

So here's my issue:
I have a database table where I have latitudes and longitudes and a timestamp. I need to be able to search through this table using PHP. What would the query be to find rows with lats and lons in a certain range, and, on top of this, in a certain time frame.
I have found two separate queries that would work while browsing through the internet, but I can't find a clear way to combine multiple conditions.
The two queries are:
SELECT id, ( 3959 * acos( cos( radians(37) ) * cos( radians( lat ) ) *
cos( radians( lng ) - radians(-122) ) + sin( radians(37) ) *
sin( radians( lat ) ) ) ) AS distance
FROM markers
HAVING distance < 25
ORDER BY distance
LIMIT 0 , 20;
enter code here
SELECT * FROM `table` WHERE `date_field` BETWEEN 'date1' AND 'date2'
I need to find top twenty results where timestamp and lat and long are in range.
Thanks!
EDIT: All fields are in the same table.
If all data is in the same table, you can do:
SELECT id, ( 3959 * acos( cos( radians(37) ) * cos( radians( lat ) ) * cos( radians( lng ) - radians(-122) ) + sin( radians(37) ) * sin( radians( lat ) ) ) ) AS distance
FROM markers
WHERE date_field BETWEEN 'date1' AND 'date2'
HAVING distance < 25
ORDER BY distance
LIMIT 0 , 20;

Processor issues with LEFT JOIN query

This may or may not be a simple question.
I have a query which selects all locations within a mile radius around a provided latitude and longitude. That part works perfectly, but I have additional information inside of another table that I would like to match to it. I've tried LEFT JOIN, but it's timing out.
SELECT *,
( 3959 * acos( cos( radians(40.7143528) ) * cos( radians( lat ) )
* cos( radians( lon ) - radians(-74.0059731) ) + sin( radians(40.7143528) )
* sin( radians( lat ) ) ) ) AS distance
FROM locations
LEFT JOIN informations ON
locations.name = informations.name
HAVING distance < 1
Here is what I would like this query to do:
Provide all matching locations within a mile radius (works)
Obtain the name of those stores (works)
Match those names against the names of each store in the "informations" table
Join all of the information in the matching rows together, where "locations.name" and "informations.name" match
The above query seems like it wants to work. I don't get any errors and it shows as valid in any MySQL formatter I use. However, I think I'm making an error somewhere which causes my tiny server to max processor usage.
To a more experienced set of eyes, would you see a reason why this would occur? Other than my server being near useless, of which I'm aware.
Make your initial query a sub-query of the main query, and left join that resulting relation to the new table (with additional information). That should give you performance back
The result will look like this:
SELECT *
FROM(
SELECT *,
( 3959 * acos( cos( radians(40.7143528) ) * cos( radians( lat ) )
* cos( radians( lon ) - radians(-74.0059731) ) + sin( radians(40.7143528) )
* sin( radians( lat ) ) ) ) AS distance
FROM locations
) locations
LEFT JOIN informations
ON location.name =informations.name
The HAVING clause is of course part of query #1.
I use SQL SERVER typically, so the syntax may not be quite right for MYSQL.