MySQL Logic issue using 'Between' to calculate coordinates - mysql

I have a table that contains a list of stores, with Latitude and Longitude.
I doing the following query:
SELECT store_name, latitude FROM (`stores`)
WHERE (latitude BETWEEN '-1' AND '-12')
The Result:
"BELEM UMARIZAL" "-1.4454262"
"BELEM NAZARE DUQUE" "-1.454061"
"BELEM SUPERCENTER NAZARE" "-1.4595652"
"BELEM BATISTA CAMPOS" "-1.459802"
"ARACAJU" "-10.9336128"
"BELEM DOMINGOS MARREIROS" "-1.4443628"
"PALMAS " "-10.178152"
"SINOP" "-11.8573162"
"ARACAJU JARDINS" "-10.942702"
SELECT store_name, latitude FROM (`stores`)
WHERE store_name like '%RIO BRANCO%'
The Result:
"RIO BRANCO" "-9.9462713"
"RIO BRANCO AVIƁRIO" "-9.965754700000002"
Why these stores are not in the first result?
What I am missing?
Best Regards!

Presumably, you are storing the values as strings not as numbers. Hence, the comparisons are done as strings. One way to fix this is to use silent conversion:
SELECT store_name, latitude
FROM stores
WHERE latitude + 0 BETWEEN -12 AND -1;
However, if you want to treat the values as numbers, you should store them as numbers. I would recommend DECIMAL(10, 6).
Note:
As originally written, the expression:
WHERE latitude + 0 BETWEEN -1 AND -12
would return no rows, because -1 is larger than -12 and the operands to BETWEEN should be in order. However, do note that it does work with strings . . . further indicating the difference between string and numeric comparisons.

Related

How to output calculation to 4 decimal places

I am in SQL Workbench and want my output to include 4 decimal places. I have tried different combinations of casting 'sessions', 'transactions', and 'cvr' as DECIMAL as well as using ROUND, and I can't seem to get the output I'm looking for. 'sessions' and 'transactions' are both in NUMERIC(19,2) format.
Ideally, I want to stay away from casting to float to avoid losing precision.
select cast((transactions/sessions) as decimal(10,5)) as cvr
from(select name
,sum(cast(sessions as decimal(10,5))) as sessions
,sum(cast(transactions as decimal(10,5))) as transactions
How to get output with 4 decimal places
SELECT FORMAT(123.456789, 4) as col
123.4567
SELECT FORMAT(123.456, 4) as col
123.4560

How to get more precision for a computed distance in MySQL, without using geometric types?

I must compute the distance between an object (a city) and each of the several entries from a MySQL table I have (some restaurants). This city and the restaurants are located in a same country.
The computed distance is used in order to show all the restaurants which are close to this city ; the threshold distance is arbitrary. Moreover, this is a ranked list: the closest restaurants are shown first, and the farest are shown at end-of-list. My problem is about this ranking.
What I've done for now
So I made some researches and I succeeded in computing this distance.
$special_select_distance = "DEGREES(ACOS(COS(RADIANS(" . $oneVilles->__get('latitude')[app::getLang()] . ")) * COS(RADIANS(lat)) * COS(RADIANS(lon) - RADIANS(" . $oneVilles->__get('longitude')[app::getLang()] . ")) + SIN(RADIANS(" . $oneVilles->__get('latitude')[app::getLang()] . ")) * SIN(RADIANS(lat))))";
$restaurants = $restaurantsDAO->getAll(null, ['distance DESC'] , null, 'HAVING distance < 1.9' , null , '*, ' . $special_select_distance . " AS distance");
... where:
['distance DESC'] stands for the ranking by distance
'HAVING distance < 1.9' stands for the arbitrary threshold
'*, ' . $special_select_distance . " AS distance" is the selector
$oneVilles->__get('latitude')[app::getLang()] and $oneVilles->__get('longitude')[app::getLang()] are the city's coordinates lat and lon
lat and lon are the restaurant's coordinates (automatically taken into the table we are iterating on, i.e.: restaurants table, since we use the restaurants DAO)
Question
Actual and unexpected result
For each of the restaurants that are quite close between themselves, the computed distance with the city remains the same.
Example: assume that restaurants A and B are quite close. Then, the distance between A and the city is the same than B and the city, it's my actual and unexpected result.
This is not what I want. Indeed, in reality one of these restaurants is closest to the city than the other. I think there isn't enough precision in MySQL.
Expected result
Expected result: to make the restaurants ranking according to the distance to the city working. In other words, to get a more precise computed distance.
Example: assume that restaurants A and B are quite close. Then, the distance between A and the city is shorter than B and the city, it's my expected result.
Examples of computed distances
Between a restaurant and the city (the restaurant being far from the city): 1.933156948976873
Between a restaurant A and the city (A being close to the city): 1.6054631070094885
Between a restaurant B and the city (B being close to A): 1.6054631070094885
Distances in points 2. and 3. are the same and it's not normal. I would want to have more digits, in order to be able to rank my restaurants more efficiently.
Constraints
I wouldn't want to change the configuration of the MySQL Server.
In particular: I absolutely can't use MySQL geometric types (it's a firm's constraint)
The expected solution should simply change the SQL query I wrote and provided to you, in order to be more precise, if it's possible.
Other methods of calculating the distance are allowed, if necessary.
For long distances, use the Haversine formula for accuracy. For short distances, Pythagoras is twice as fast.
16 significant digits (data type DOUBLE) is ludicrous. You don't need to distinguish two different fleas on your dog.
With Pythagoras, be sure to divide the longitude by the cosine of the latitude -- One degree of longitude near Helsinki is half as far as one degree at the equator.
Some more details here: http://mysql.rjweb.org/doc.php/latlng
If 1.6054631070094885 is a latitude diff, then think about it this way: If you and I are at the same longitude, but our latitudes are 1.605463 and 1.605464, then, well, I don't know you well enough to be that close.
It is not practical to compare two floating point values without having a fudge factor:
If abs(a-b) < 0.00001, then treat them as equal.
More
I recommend FLOAT for lat, lng, and distance since you are talking about restaurants. If you are not talking about more than, say, 100 miles or km, then this expression is sufficiently precise:
SQRT( ($lat - lat) *
($lat - lat) +
(($lng - lng) * COS(RADIANS(lat))) *
(($lng - lng) * COS(RADIANS(lat))) ) * $factor
Where...
lat and lng are names of FLOAT columns in the table, in units of degrees.
$lat and $lng are values of the location you are starting from, also in degrees. (PHP uses $; other languages use other conventions.)
$factor is 69.172 for miles or 111.325 for kilometers.
I would not display the result with more than perhaps 1 decimal place. (Don't display "12.345678 miles"; "12.3 miles" is good enough.)
A comparison of Pythagoras and GCD:
Pyt GCD
To Rennes: 93.9407 93.6542
To Vannes: 95.6244 95.6241

Retrieve coordinates from MySQL Geometry column

I just started using the MySQL Geospatial extension in hope of speeding up lat/lng range searches in my database of 500K points. A new GEOMETRY column p is created.
Problem:p & AsText(p) values returned are simply (BLOB), not in decimal degrees. No values are returned by GeomFromText(p). Because I had the redundant lat and lng columns, I still manage to get the lat lng values that I need. But I'm thinking of removing the lat and lng cols and just rely on p.
Converted existing Lat/Lng values to Points
UPDATE listings SET p = GeomFromText('POINT(39.948177 -75.174324)') WHERE listing_id = '585221';
Attempt to Retrieve Lat Lng from GEOMTRY col p
SELECT listing_id, lat, lng, GeomFromText(p), AsText(p), p from listings WHERE MBRContains( GeomFromText('Polygon((39 -76, 40 -76, 40 -74, 39 -74, 39 -76))'), p)
If you use AsText you will get your object in WKT format. To extract point coordinates use:
SELECT listing_id X(p), Y(p)
FROM listings
WHERE MBRContains( GeomFromText('Polygon((39 -76, 40 -76, 40 -74, 39 -74, 39 -76))'), p)
MySQL probably returns result of AsText as BLOB because it can get really long for complex objects. It's just that whatever you are using to display results can't cope with that, but the text is there.

Why doesn't this sql query return any results comparing floating point numbers?

I have this in a mysql table:
id and bolag_id are int. lat and lngitude are double.
If I use the the lngitude column, no results are returned:
lngitude Query: SELECT * FROM location_forslag WHERElngitude= 13.8461208
However, if I use the lat column, it does return results:
lat Query: SELECT * FROM location_forslag WHERElat= 58.3902782
What is the problem with the lngitude column?
It is not generally a good idea to compare floating point numbers with = equals operator.
Is it correct to compare two rounded floating point numbers using the == operator?
Dealing with accuracy problems in floating-point numbers
For your application, you need to consider how close you want the answer to be.
1 degree is about 112km, and 0.00001 degrees is about 1.1 metres (at the equator). Do you really want your application to say "not equal" if two points are different by 0.00000001 degrees = 1mm?
set #EPSLION = 0.00001 /* 1.1 metres at equator */
SELECT * FROM location_forslag
WHERE `lngitude` >= 13.8461208 -#EPSILON
AND `lngitude` <= 13.8461208 + #EPSILON
This will return points where lngitude is within #epsilon degrees of the desired value.
You should choose a value for epsilon which is appropriate to your application.
Floating points are irritating....
WHERE ABS(lngitude - 13.8461208) < 0.00000005
Convert float to decimal for compare. I had the same problem and solved like this:
SELECT
[dbo].[Story].[Longitude],
[dbo].[Story].[Latitude],
[dbo].[Story].[Location],
FROM
[dbo].[Story],
[dbo].[Places]
WHERE
convert(decimal, [dbo].[Story].[Latitude]) = convert(decimal, [dbo].[Places].[Latitude])
and
convert(decimal, [dbo].[Story].[Longitude]) = convert(decimal, [dbo].[Places].[Longitude])
and
[dbo].[Places].[Id] = #PlacesID
and
[dbo].[Story].IsDraft = 0
ORDER BY
[dbo].[Story].[Time] desc
Look at the first 3 rows after the WHERE clausule.
Hope it helps.

Update Decimal valued fields in SQL Server

I want to do the following to my database:
UPDATE Addresses
SET Latitude = 1000, Longitude = 1000
WHERE Latitude IS NULL AND Longitude IS NULL
1000 is not a valid latitude or longitude. Latitude and Longitude are new columns in my database, and I don't want any of the fields to be null. I handle invalid latitude and longitude values in my application, but having them null creates difficulties.
When I try to run this query, I get the following error:
Msg 8115, Level 16, State 8, Line 3
Arithmetic overflow error converting int to data type numeric.
The statement has been terminated.
The datatypes of the Latitude and Longitude column are both Decimal(18,15). I assume that I have to write these decimal entries in a particular way, but I can't work out what it is.
Could someone enlighten me?
You are overflowing your specified parameters for the datatype.
DECIMAL(18,15) means you have 18 total places, and 15 of those are right of the decimal. This leaves 3 places left of the decimal, and 1000 is a four digit number.
You need to either change the datatype to something like DECIMAL(18,14) or use a value like 999.999999999999999.