Why Mysql does not find records that exists. It is about Lat&Lng database search - mysql

what could possible be the reason for Mysql does not find records that exists. It is about Lat&Lng database search. I have this simple query:
select id from addresses where lat = "42.5632172" and lng = "27.5266380"
which returns 0 results but its obvious that record exists.
Here is my database structure and records:
Thanks in advance for your time!

Since data type of your lat and lng columns is float which is not a precision data type, so comparing on this data type often lead to unexpected result. It's better to use some tolerance when comparing values of these float columns.
SELECT id
FROM addresses
WHERE ABS(lat - 42.5632172) <= 0.0000001
AND ABS(lng - 27.5266380) <= 0.0000001
But it's much better if you could change data type of your columns to precision number data type, such as DECIMAL.
See demo here.

Related

Not getting max value more than 'D99999' in MySQL from varchar column

Deposit_number
--------------
D100000
D99999
D50
.....
D4
D3
D2
D1
I am trying to get record by using following JPA query deposit
Deposit findTopByCompanyOrderByDepositNumberDesc(Company company);
But in result I am getting record which containing 'D99999' and I am expecting 'D100000'. Please help if any one have idea to fix this problem. I want to solve this using a JPA query, not by using a SQL native query.
The problem is that your Deposit_number column is text, but you are expecting the numbers to sort as numbers, not text. Assuming the D is a constant prefix, and only non numeric character, throughout the column, we can try the following MySQL query:
SELECT *
FROM yourTable
ORDER BY CAST(SUBSTRING(Deposit_number, 2) AS SIGNED) DESC;
Does this query look ugly? Yes, it does, but then again the way you are storing your deposit numbers is also ugly. If you don't want to have to use the above query, then consider storing the deposit numbers in a separate column.

how to display the value of avg function till only two decimal places in SQL?

select avg(purch_amt) from orders;
I took an average of the amounts and it shows value till many decimal places and I would like to limit it to two decimal places.
Here's what I have tried:-
select cast(avg(purch_amt) as decimal(10,2)) from orders;
please answer containing both the operations(first average and then conversion). I would like to know the correct syntax of writing both the statements together.
You can update your query to:
select ROUND (avg(purch_amt),2) as Average from orders;
You can use ROUND as
SELECT ROUND(AVG(purch_amt), 2) AS 'Average' from orders
or if you want to Round all column values before calculating average
SELECT AVG(ROUND(purch_amt, 2)) AS 'Average' from orders
My preferred method is to cast to an appropriate decimal value:
select cast(avg(purch_amt) as decimal(10, 2))
from orders;
This is a bit different from round(), although the two generally produce the same result. As the documentation explains for round():
The return value has the same type as the first argument (assuming
that it is integer, double, or decimal)
That means that what gets displayed in an application might still show more (or fewer) than the number of decimal places. By changing the type, the application will know how many decimal places should be in the result.
You can see from this example that round() does not change the data type -- hence it might not change the representation in a tool.

My Query is too slow

My query that I made is too slow. It takes more than one minute. How can I quickly create a query?
Can you help me?
select * from nss_sikdan_ok where od_id in(
select od_id from nss_order od
join nss_cart ct on od.on_uid=ct.on_uid
where ct.ct_status in('cart','sell')) and (DATE_FORMAT(today_end_date,'%Y-%m-%d')='2017-05-05') and today_end='1' limit 0,1
There are few things you can do to optimize this query.
On the query side:
Avoid calling functions on potentially indexed columns - as it won't allow MySQL to use the index on that column. The following condition:
DATE_FORMAT(today_end_date,'%Y-%m-%d')='2017-05-05'
Can be modified to this one, to avoid using the DATE_FORMAT function on the indexed column and instead only use functions on constant values:
today_end_date >= DATE('2017-05-05') AND today_end_date < (DATE('2017-05-05') + INTERVAL 1 DAY)
====
Do not use OFFSET values in your query - Instead of LIMIT X,Y, you can use the alternative approach for faster pagination with offset in MySQL.
===
Avoid selecting unused columns - in most cases, selecting all columns using the '*' operator will cause performance issues, as you're fetching more information than you actually need. Think about which columns you actually need in the result set and fetch them.
===
Use numeric values whenever appropriate - When comparing a numeric column to a string, you're forcing MySQL to cast the column's value for each row from a number to a string and only then perform the comparison. Therefore, in the condition today_end='1', if today_end is a numeric column, the condition should be:
today_end = 1
Instead of:
today_end = '1'
===
Also, if you can provide the schema structure, it will be possible to recommend the appropriate indexes for this situation.
By the way, I got the recommendations from this online MySQL query optimizer, so feel free to just enter your query and schema there and get indexing recommendations as well.

mysql geolat geolng multi indexed query

I have a table with fields 'lat', and 'lng'. Both are pretty much continuous, meaning they don't repeat themselves much. This has led me to believe that making a multi-column index for lat and lng wouldn't really help me. What I'd LIKE to do is this:
Make an index on both lat and lng, and then perform a query like:
select from tableName where
lat >= 13.1232 and lat <=14.123 and
lng >=-80.123 and lng <=-79.232 and
name like '%greg%'
and have mysql perform this process:
select all LATs between 14.1232 and 13.123 (this should be indexed, and fast)
within the group that step#1 found, perform step#2: find lngs <=-80.123 and lngs>= -79.232 (this should also be indexed and very fast)
3.within the group created by steps #1 and #2... perform the more time-consuming key-word search.
How can I do this? I'm pretty sure that the first part of the query (the indexed lat) is narrowing things down for me... but after that I'm not sure... and this is what I've been struggling to find in the docs
MySQL handles conventional B-tree indexes like most implementations: The index helps only the range condition on the leftmost columns in the index.
The analogy I use is to a telephone book. If I search for a specific last name, first name pair like "Smith, John" the index helps. My search for the last name "Smith" is quick, and within the Smiths, the search for "John" is quick.
But if I search for a range condition like "all people whose last name begins with 'S'", then I get a subset of the telephone book but not all the people named "John" are sorted together. They're scattered through the subset I selected based on last name.
It's for this reason that MySQL searches a B-tree index up to the first range condition, and then does not use the index any further. You can still make conditions for the other dimension, but it will do a manual search through all the rows matched by the first dimension.
In other words, even if you have a compound index on (lat, long), MySQL will not use the long part of the index:
select ... from tableName
where lat >= 14.1232 and lat <=13.123 /* index-assisted */
and lng >=-80.123 and lng <=-79.232 /* full scan */
and name like '%greg%' /* pattern search never uses index anyway */
(By the way, your lat condition can never be true as you have written it, but I'll assume you mean the numbers to be reversed.)
This makes it inefficient to do latitude & longitude conditions, since both are search for a range of values.
For this reason, MySQL has another type of index, which is not a B-tree index. It's a SPATIAL index, which does support multiple range conditions.
CREATE TABLE mytable (
name TEXT NOT NULL,
coord POINT NOT NULL,
SPATIAL INDEX (coord)
);
INSERT INTO mytable (name, coord)
VALUES ('name', ST_GeomFromText('POINT(14.0 -80)'));
SELECT name FROM mytable
WHERE MBRContains(
ST_GeomFromText('Polygon((
13.123 -80.123,
14.1232 -80.123,
14.1232 -79.232,
13.123 -79.232,
13.123 -80.123))'),
coord);
Yes, this is more complex, but it's the only way you can get truly index-optimized latitude/longitude searches.
Read more about it here: http://dev.mysql.com/doc/refman/5.7/en/using-spatial-data.html
If you absolutely want each where clause to limit the result set in order you could try something like this but an sql optimizer might change things under the cover. I think a good index or two is still your best bet but I believe this is what you are asking for. I recommend Explain Plan to optimize your queries.
select * from
(
select * from
(
select * from tableName
where lat >= 14.1232 and lat <=13.123
)
where lng >=-80.123 and lng <=-79.232
)
where name like '%greg%'

MySQL - Use min function or limit an order-by query

I am writing a query to find the product with the minimum price.
These are the two queries I tried:
select min(price) from products
and
select price from products order by price limit 1
The first one returns 19.950000762939453 and the second one returns 19.95 which is the accurate value. So my question is, what's the difference of the two queries?, why is the first one weird?! and which has a better performance for this task?
Thanks in advance.
Your data type of price is probably a floating-point with is by definition inaccurate.
If you use a fixed-point data type like decimal it will be 19.95.
You can read it up in the doc
min has better performance, according strange values - you should read how floating numbers are stored in memory/db, they are "rounded"
if you store real price - go with DECIMAL type, it will work fine