I have posted a question here earlier and got an awesome answer!
Stuck in building mysql query
But it lacks a one moment!
I am having a column in mysql table, defined as:
`bet_price` float(10,2) NOT NULL DEFAULT 0.00,
For a certain row the value is: 10000
A query like: SELECT bet_price, MIN(bet_price) AS min_price WHERE ID = :id
Will return a data like this:
bet_price | min_price
---------------------
10000 | 10000.00
And in queries this part fails for me.
I've tried to use a functions like FORMAT and TRUNCATE - but this did not help me.
could be there are some implicit conversion of some conversion in output rendering so if you need always same value then cast properly
cast(a.bet_price as decimal(10,2), MIN(b.bet_price)
or
a.bet_price , cast(MIN(b.bet_price) as UNSIGNED)
Related
I was doing some system testing and expecting empty results from MySQL(5.7.21) but got surprised to get results.
My transactions table looks like this:
Column Data type
----------------------------
id | INT
fullnames | VARCHAR(40)
---------------------------
And I have some records
--------------------------------
id | fullnames
--------------------------------
20 | Mutinda Boniface
21 | Boniface M
22 | Some-other Guy
-------------------------------
My sample queries:
select * from transactions where id = "20"; -- gives me 1 record which is fine
select * from transactions where id = 20; -- gives me 1 record - FINE as well
Now it gets interesting when I try with these:
select * from transactions where id = "20xxx"; -- gives me 1 record - what is happening here?
What does MySQL do here??
MySQL plays fast and loose with type conversions. When implicitly converting a char to a number, it will take characters from the beginning of the string as long as they are digits, and ignore the rest. In your example, xxx aren't digits, so MySQL only takes the initial "20".
One way around this (which is horrible for performance, since you lose the usage on the index you may have on your column), is to explicitly cast the numeric side to a character:
SELECT * FROM transactions WHARE (CAST id AS CHAR) = 20;
EDIT:
Referencing the discussion about performance from the comments - performing the cast to a number on the client-side is probably the best approach, as it will allow you to avoid sending queries to the database when you know no rows should be returned (i.e., when your input is not a valid number, such as "20x").
An alternative hack could be to cast the input to a number and back again to a string, and compare the lengths. If the lengths are the same it means the input string was fully converted into a number and no characters were omitted. This should be OK WRT performance, since this comparison is performed on an inputted string, not on a value from the column, and the column's index can still be used if the condition passes the short-circuit evaluation of the input:
SELECT *
FROM transactions
WHERE LENGTH(:input) = LENGTH(CAST(:input AS SIGNED)) AND id = :input;
I've stumbled on a previously asked and answered question here:
How to use comparison operator for numeric string in MySQL?
I absolutely agree with the answer being the best mentioned. But it left me with a question myself while I was trying to create my own answer. I was trying to select the first number and convert it to an integer. Next I wanted to compare that integer with a number (3 in case of the question).
This is the query I've created:
SELECT experience,
CONVERT(SUBSTRING_INDEX(experience,'-',1), UNSIGNED INTEGER) AS num
FROM employee
WHERE #num >= 3;
For the sake of simplicity, asume the data inside experience is: 4-8
The query doesn't return any errors. But it doesn't return the data either. I know it's possible to compare the data inside a column with a user defined variable. But is it possible to compare data (the integer in this case) with the variable like I'm trying to do?
This is purely out of curiousity and to learn something.
Yes, a derived table will do. The inner select block below is a derived table. And every derived table needs a name. In my case, xDerived.
The strategy is to let the derived table cleanse the use of the column name. Coming out of the derived chunk is a clean column named num which the outer select is free to use.
Schema
create table employee
( id int auto_increment primary key,
experience varchar(20) not null
);
-- truncate table employee;
insert employee(experience) values
('4-5'),('7-1'),('4-1'),('6-5'),('8-6'),('5-9'),('10-4');
Query
select id,experience,num
from
( SELECT id,experience,
CONVERT(SUBSTRING_INDEX(experience,'-',1),UNSIGNED INTEGER) AS num
FROM employee
) xDerived
where num>=7;
Results
+----+------------+------+
| id | experience | num |
+----+------------+------+
| 2 | 7-1 | 7 |
| 5 | 8-6 | 8 |
| 7 | 10-4 | 10 |
+----+------------+------+
Note, your #num concept was faulty but hopefully I interpreted what you meant to do above.
Also, I went with 7 not 3 because all your sample data would have returned, and I wanted to show you it would work.
The AS num instruction names the result of convert as num, not a variable named #num.
You could repeat the convert
SELECT experience,CONVERT(SUBSTRING_INDEX(experience,'-',1),UNSIGNED INTEGER)
FROM employee
WHERE CONVERT(SUBSTRING_INDEX(experience,'-',1),UNSIGNED INTEGER) >= 3;
Or use a partial (derived) table (only one convert)
SELECT experience,num
FROM (select experience,
CONVERT(SUBSTRING_INDEX(experience,'-',1),UNSIGNED INTEGER) as num
FROM employee) as partialtable WHERE num>=3;
Much simpler. (Or at least much shorter.) This will work for the data as described, namely "number, -, other stuff".
SELECT experience,
0+experience AS 'FirstPart'
FROM employee
WHERE 0+experience >= 3
Why? 0+string is parsed as "convert the string to a number, then add it to 0". Converting a string will extract the digits up to the first non-digit, then convert that as numeric.
I was experimenting with mysql, and made a query to compare two different fields using the GRATEST() function.
My query looks like this:
SELECT
id,
float1,
float2,
GREATEST(
IFNULL(float1, 0),
IFNULL(float2, 0)
) AS gtst
FROM `test`
Float1 and 2 are UNSIGNED FLOAT, with NULL as default value.
Server version: 5.1.73-1-log, client: 5.0.8-dev, PHP extension: mysqli.
Running the above command gives me strange values like this:
| id | float1 | float2 | gtst |
|-----|--------|--------|------------------|
| 872 | 348.5 | 348.58 | 348.579986572266 |
I know that MySQL handles floating point values strangely, as it is described in this article, but it's unclear to me where are these extra digits coming from?
A single comparison shouldn't alter the supplied values, right? There's no mathematical equations here where rounding errors could come into play, so what could be wrong?
Thanks in advance!
Its seems like you have declared float1 and float2 as float datatype, which usually takes 12 fractional points like 10.123456789101 make use of
Round(10.123456789101,2);
to display 2 extra digits as, 10.12
I need to treat a date field in mySQL as if it is a string. For the purposes of using the date in a LIKE statement:
select * from table where dob like some_string;
Doing this currently produces the following warning:
mysql> show warnings;
+---------+------+--------------------------------------------------------+
| Level | Code | Message |
+---------+------+--------------------------------------------------------+
| Warning | 1292 | Incorrect date value: '1492' for column 'dob' at row 1 |
+---------+------+--------------------------------------------------------+
1 row in set (0.00 sec)
I would use DATE_FORMAT to get a string representation of your DATE column:
SELECT
*
FROM
yourtable
WHERE
DATE_FORMAT(dob, '%Y-%m-%d') LIKE '1492%';
and use the pattern that suits your need best. You find the specifiers right in the linked manual page.
Note:
MySQL can't use an index for this kind of query, so it will be slow.
Use a cast
Select *
From Table
Where Cast(dob as nvarchar(20)) Like some_string;
using the date in a LIKE statement
No. Things that this approach does wrong:
Wastes CPU time converting dates to strings.
Wastes time doing string comparisons when integer comparisons could be done.
Throws away any index on dob that might otherwise make the query more efficient.
A better approach would be something like:
SELECT *
FROM table
WHERE dob BETWEEN '1492-01-01' AND '1492-12-31'
You will always want to do as few type conversions as possible and keep the table data as-is so that indexes are properly utilized.
After searching, I found plenty of out of range problems with people not knowing that the first digit, m, in decimal(m,n) is the total amount of digits. However, that is not my problem.
For the column in question I have the following:
Field | Type | Null | Key | Default | Extra
preco | decimal(50,2) unsigned | NO | | 0.00 |
The setting decimal(50,2) is way more than I really want or need. I really only want 10 digits total. Its a price, so anything over 100 million is probably ridiculous, so decimal(10,2) would probably be more appropriate. However, MySQL Is not accepting the following query:
INSERT INTO `produto` (`tipo_id`, `preco`, `qtd`, `opcao1`) VALUES (110, '77888555.43', '10', 'Azul')
I tried the query through CodeIgniter, phpMyAdmin and directly in the MySQL command line client. I also tried it without the quotes on the decimal value but I always get the same error:
"Out of range value for column 'preco' at row 2"
You are sending the value for preco as a string which is accepted by MySQL in the same way as a numerical value.
I have tried it with SQLyog, it is working perfect. I tried to change both ways in SQLyog directly through Table Data tab and using Query. It is just working. it seems there is no problem in Decimal Range, but problem is some where else. See the screenshots attached
Directly through Table Data Tab
Through insert query
Table Structure
Hope it help...