CAST DECIMAL to INT - mysql

I'm trying to do this:
SELECT CAST(columnName AS INT), moreColumns, etc
FROM myTable
WHERE ...
I've looked at the help FAQs here: http://dev.mysql.com/doc/refman/5.0/en/cast-functions.html , it says I can do it like CAST(val AS TYPE), but it's not working.
Trying to convert a decimal to int, real value is 223.00 and I want 223

You could try the FLOOR function like this:
SELECT FLOOR(columnName), moreColumns, etc
FROM myTable
WHERE ...
You could also try the FORMAT function, provided you know the decimal places can be omitted:
SELECT FORMAT(columnName,0), moreColumns, etc
FROM myTable
WHERE ...
You could combine the two functions
SELECT FORMAT(FLOOR(columnName),0), moreColumns, etc
FROM myTable
WHERE ...

A more optimized way in mysql for this purpose*:
SELECT columnName DIV 1 AS columnName, moreColumns, etc
FROM myTable
WHERE ...
Using DIV 1 is a huge speed improvement over FLOOR, not to mention string based functions like FORMAT
(graphic from Roland Bouman's blog)
mysql> SELECT BENCHMARK(10000000,1234567 DIV 7) ;
+-----------------------------------+
| BENCHMARK(10000000,1234567 DIV 7) |
+-----------------------------------+
| 0 |
+-----------------------------------+
1 row in set (0.83 sec)
mysql> SELECT BENCHMARK(10000000,1234567 / 7) ;
+---------------------------------+
| BENCHMARK(10000000,1234567 / 7) |
+---------------------------------+
| 0 |
+---------------------------------+
1 row in set (7.26 sec)
mysql> SELECT BENCHMARK(10000000,FLOOR(1234567 / 7)) ;
+----------------------------------------+
| BENCHMARK(10000000,FLOOR(1234567 / 7)) |
+----------------------------------------+
| 0 |
+----------------------------------------+
1 row in set (8.80 sec)
(*) NOTE: As pointed by Grbts, be aware of the behaviour of DIV 1 when used with non unsigned/positive values.

From the article you linked to:
The type can be one of the following values:
BINARY[(N)]
CHAR[(N)]
DATE
DATETIME
DECIMAL[(M[,D])]
SIGNED [INTEGER]
TIME
UNSIGNED [INTEGER]
Try SIGNED instead of INT

The CAST() function does not support the "official" data type "INT" in MySQL, it's not in the list of supported types. With MySQL, "SIGNED" (or "UNSIGNED") could be used instead:
CAST(columnName AS SIGNED)
However, this seems to be MySQL-specific (not standardized), so it may not work with other databases. At least this document (Second Informal Review Draft) ISO/IEC 9075:1992, Database does not list "SIGNED"/"UNSIGNED" in section 4.4 Numbers.
But DECIMAL is both standardized and supported by MySQL, so the following should work for MySQL (tested) and other databases:
CAST(columnName AS DECIMAL(0))
According to the MySQL docs:
If the scale is 0, DECIMAL values contain no decimal point or
fractional part.

use this
mysql> SELECT TRUNCATE(223.69, 0);
> 223
Here's a link

There is an important difference between floor() and DIV 1. For negative numbers, they behave differently. DIV 1 returns the integer part (as cast as signed does), while floor(x) returns "the largest integer value not greater than x" (from the manual). So : select floor(-1.1) results in -2, while select -1.1 div 1 results in -1

your can try this :
SELECT columnName1, CAST(columnName2 AS SIGNED ) FROM tableName

There's also ROUND() if your numbers don't necessarily always end with .00. ROUND(20.6) will give 21, and ROUND(20.4) will give 20.

Try cast (columnName as unsigned)
unsigned is positive value only
If you want to include negative value, then cast (columnName as signed),
The difference between sign (negative include) and unsigned (twice the size of sign, but non-negative)

1 cent:
no space b/w CAST and (expression).
i.e., CAST(columnName AS SIGNED).

Related

MySQL FLOOR function unexpected results

CREATE TABLE table_name (col_a double(10,2), col_b double(10,2), col_c double(10,2));
INSERT INTO table_name VALUES(36.3, 0, 6.3);
QUERY
SELECT FLOOR(36.3- 0 -6.3), FLOOR(col_a - col_b - col_c) AS calc, col_a, col_b, col_c
FROM table_name LIMIT 1;
RESULT
first selected value => FLOOR(36.3- 0 -6.3) result in 30.
second selected value => FLOOR(col_a - col_b - col_c) which is equals to FLOOR(36.3- 0 -6.3) result in 29 but i am expecting 30
Why these selects getting two different values?
This is a known problem in MySQL when using the double or float type, which are not stored internally exactly as we see them.
If you read the MySQL documentation, you will find a suggested workaround which is to use decimal instead of double. You can see in the following Fiddle that all is working as expected when using decimal(10,2) as your column types:
SQLFiddle
The values you put in the select are automatically taken as decimal and that's why the result is correct.
select 36.3 - 0 - 6.3
--Produces
30.0
Floating point types are not stored exactly, so you'll not get the exact results. Try this:
select 36.3E0 - 0E0 - 6.3E0
--Produces
29.999999999999996
and hence floor gives you 29 in the output.
From https://dev.mysql.com/doc/refman/5.5/en/floating-point-types.html
Because floating-point values are approximate and not stored as exact
values, attempts to treat them as exact in comparisons may lead to
problems. They are also subject to platform or implementation
dependencies.
And from https://dev.mysql.com/doc/refman/5.5/en/problems-with-float.html
A floating-point value as written in an SQL statement may not be the
same as the value represented internally.
As Tim advised, you should use Decimal type instead.
This is because floor(-6.3) is 7 .Hence it will become 29.
Further details you can check on https://msdn.microsoft.com/en-us/library/ms178531.aspx
Binary floating point it is based on the IEEE 754 standard for float and double.
when you insert value 36.3 into the column which has datatype double then its stores as '36.29999923706055' and for 6.3 - > '6.300000190734863'
You can convert from here Link 1 or Link 2
Now Result col_a - col_b - col_c is '29.99999904632569'.
Now you applied floor on it which give you result '29'
FLOOR() returns the largest integer value not greater than a number specified as an argument.
floor (col_a - col_b - col_c)
Returns output floor(29.99999904632569) which give you answer - > 29
As Tim advised, you should use Decimal type instead or use below query.
SELECT FLOOR(36.3- 0 -6.3),(col_a - col_b - col_c)
AS calc, col_a, col_b, col_c
FROM table_name LIMIT 1;
Output : 30

MySQL VARCHAR Type won't CONVERT to Integer

I have a column of data of type VARCHAR, that I want to CONVERT or CAST to an integer (my end goal is for all of my data points to be integers). However, all the queries I attempt return values of 0.
My data looks like this:
1
2
3
4
5
If I run either of the following queries:
SELECT CONVERT(data, BINARY) FROM table
SELECT CONVERT(data, CHAR) FROM table
My result is:
1
2
3
4
5
No surprises there. However, if I run either of these queries:
SELECT CONVERT(data, UNSIGNED) FROM table
SELECT CONVERT(data, SIGNED) FROM table
My result is:
0
0
0
0
0
I've searched SO and Google all over for an answer to this problem, with no luck, so I thought I would try the pros here.
EDIT/UPDATE
I ran some additional queries on the suggestions from the comments, and here are the results:
data LENGTH(data) LENGTH(TRIM(data)) ASCII(data)
1 3 3 0
2 3 3 0
3 3 3 0
4 3 3 0
5 3 3 0
It appears that I have an issue with the data itself. For anyone coming across this post: my solution at this point is to TRIM the excess from the data points and then CONVERT to UNSIGNED. Thanks for all of the help!
FURTHER EDIT/UPDATE
After a little research, turns out there were hidden NULL bytes in my data. The answer to this question helped out: How can I remove padded NULL bytes using SELECT in MySQL
What does SELECT data, LENGTH(data), LENGTH(TRIM(data)), ASCII(data) FROM table return? It's possible your numeric strings aren't just numeric strings.
Alternately, are you using multi-byte character encoding?
I believe the query you have is fine; as it worked for me: sqlfiddle.com/#!2/a15ec4/1/3.
Makes me think you have a data problem. Are you sure there's not a return or space in the data somewhere?
you can check the data by trying to do a length or a ascii on the data to see if you have more than expected:
select ascii(data) from foo where ascii(data) not between 48 and 57 or
select length(data) as mLEN from table having mlen>1 for length.
I believe this is the correct form:
SELECT CAST(data AS UNSIGNED) FROM test;
SELECT CAST(data AS SIGNED) FROM test;
Tested here: http://sqlfiddle.com/#!8/8c481/1
Try these syntax
SELECT CONVERT(data, UNSIGNED INTEGER) FROM table
or
SELECT CAST(data AS UNSIGNED) FROM table

MySQL string cast to unsigned

If I have a string that starts with a number, then contains non-numeric characters, casting this string to an integer in MySQL will cast the first part of the string, and give no indication that it ran into any problems! This is rather annoying.
For example:
SELECT CAST('123' AS UNSIGNED) AS WORKS,
CAST('123J45' AS UNSIGNED) AS SHOULDNT_WORK,
CAST('J123' AS UNSIGNED) AS DOESNT_WORK
returns:
+-------------+---------------+-------------+
| WORKS | SHOULDNT_WORK | DOESNT_WORK |
+-------------+---------------+-------------+
| 123 | 123 | 0 |
+-------------+---------------+-------------+
This doesn't make any sense to me, as clearly, 123J45 is not a number, and certainly does not equal 123. Here's my use case:
I have a field that contains (some malformed) zip codes. There may be mistypes, missing data, etc., and that's okay from my perspective. Because of another table storing Zip Codes as integers, when I join the tables, I need to cast the string Zip Codes to integers (I would have to pad with 0s if I was going the other way). However, if for some reason there's an entry that contains 6023JZ1, in no way would I want that to be interpreted as Zip Code 06023. I am much happier with 6023JZ1 getting mapped to NULL. Unfortunately, IF(CAST(zipcode AS UNSIGNED) <= 0, NULL, CAST(zipcode AS UNSIGNED)) doesn't work because of the problem discussed above.
How do I control for this?
Use a regular expression:
select (case when val rlike '[0-9][0-9][0-9][0-9][0-9]' then cast(val as unsigned)
end)
Many people consider it a nice feature that MySQL does not automatically produce an error when doing this conversion.
One options is to test for just digit characters 0 thru 9 for the entire length of the string:
zipstr REGEXP '^[0-9]+$'
Based on the result of that boolean, you could return the integer value, or a NULL.
SELECT IF(zipstr REGEXP '^[0-9]+$',zipstr+0,NULL) AS zipnum ...
(note: the addition of zero is an implicit conversion to numeric)
Another option is to do the conversion like you are doing, and cast the numeric value back to character, and compare to the original string, to return a boolean:
CAST( zipstr+0 AS CHAR) = zipstr
(note: this second approach does allow for a decimal point, e.g.
CAST( '123.4'+0 AS CHAR ) = '123.4' => 1
which may not be desirable if you are looking for just a valid integer

Extract a set of digits from a string column in MySQL

I am trying to extract a fixed-length digits from a string column in MySQL, how can I go about doing so? The usual like and regexp doesn't work, so am pretty certain a function is needed, but unsure where to start and how to go about writing one.
Please advise.
The fixed-length digits are 10 digits and a sample of the string column:
'SGD0.00 AUTOMSG:'0179187381' is near Esso # 23:59.'
Please be advised the location of the 10 digits in the string varies.
Simple:
Just use: SUBSTR(str,x,y)
where:- str -> String,
x -> position,
y -> length
Example: SELECT SUBSTR('ABCDEFG',2,3); -> BCD
For more information visit this link:
http://www.w3resource.com/mysql/string-functions/mysql-substring-function.php
mysql> select substr("'SGD0.00 AUTOMSG:'0179187381' is near Esso # 23:59.'", 19,10);
+-----------------------------------------------------------------------+
| substr("'SGD0.00 AUTOMSG:'0179187381' is near Esso # 23:59.'", 19,10) |
+-----------------------------------------------------------------------+
| 0179187381 |
+-----------------------------------------------------------------------+
1 row in set (0.48 sec)
you may try like this:
SELECT SUBSTRING('Quadratically',5);
Syntax: SUBSTRING(str,pos)
For more info: http://dev.mysql.com/doc/refman/5.0/en/string-functions.html#function_substring
If the 10 digit number will always be preceeded with :' then you could use:
select substr(column_name, locate(":'", column_name) + 2, 10) from table_name
(assuming :' does not appear anywhere else before the number in the string)

how to sort varchar numeric columns by DESC or ASC?

I write ...
ORDER BY column ASC
but my column is VARCHAR and it sorts wrong like 1, 10, 2, instead of 1, 2, 10.
How can I do it to sort like 1, 2, 10?
order by
cast(column as float)
Notes:
Assumed you only have numbers in the columns. No "fish" or "bicycle"
empty strings CAST to zero
Edit: For MySQL. You can not cast to float
order by
cast(column as decimal(38,10))
You can cast to int...
order by cast(column as int)
DEMO
DECLARE #q as table(
name varchar(50),
columnn varchar(10)
)
insert into #q
VALUES('one','1'),('one','10'),('one','20'),('one','3'),('one','2'),('one','20')
select * from #q order by cast (columnn as int) desc
prints
-------------------------------------------------- ----------
one 20
one 20
one 10
one 3
one 2
one 1
So, Daniel, yes, it works :)
UPDATE:
order by cast(column as decimal(20,6))
Will cast the column values to decimal numbers with 20 digits max and 6 decimal places. Adjust it to your actual requirements.
Try this:
order by CAST(column as UNSIGNED)
i used this way
multiply it with one the query is :
ORDER BY columnname * 1 ASC
Example: Table user have value with column value [varchar(20)].
Then you can query it:
SELECT * FROM user ORDER BY value * 1
After we multiply it MySQL will treat it like a number but this way is not recommended for a heavy load.