Why MySQL ... why? - mysql

So, with mysql, why do things that don't equal each other, equal each other? For example, why ...
mysql> SELECT '3' = 3;
+---------+
| '3' = 3 |
+---------+
| 1 |
+---------+
Just, why?
And more importantly ...
mysql> SELECT 0 = '';
+--------+
| 0 = '' |
+--------+
| 1 |
+--------+
But, why?
Also ...
mysql> SELECT '3x' into #foo;
Query OK, 1 row affected (0.00 sec)
mysql> SELECT #foo, CAST(#foo as signed), #foo = CAST(#foo as signed);
+------+----------------------+-----------------------------+
| #foo | CAST(#foo as signed) | #foo = CAST(#foo as signed) |
+------+----------------------+-----------------------------+
| 3x | 3 | 1 |
+------+----------------------+-----------------------------+
Dear God, why?
But worse still ...
mysql> SELECT '3x', CAST('3z' as signed), '3x' = CAST('3z' as signed);
+----+----------------------+-----------------------------+
| 3x | CAST('3z' as signed) | '3x' = CAST('3z' as signed) |
+----+----------------------+-----------------------------+
| 3x | 3 | 1 |
+----+----------------------+-----------------------------+
Why, oh why? Why does it make me cry so ... ?

It's all there in the documentation:
http://dev.mysql.com/doc/refman/5.1/en/type-conversion.html
Especially in the line
In all other cases, the arguments are compared as floating-point (real) numbers.
So all your comparisons are floating-point comparisons and as such make perfect sense.
One can argue wether automatic type-conversion makes sense at all (should it be possible to compare '1' to 1?)...

Related

Get count of zeros in an integer using MySQL

Let's say I have an integer value in MySQL (10090). I need to count all occurrences of the zero digit in that number. So for the previous case it would return 3:
select count_zeros(number) from dual;
-- when number = 10090, it return 3
-- when number = 10000, it return 4
How can I do that the fastest way using a MySQL query?
You can compare the string length with and without the character you want to count.
Solution using LENGTH
-- 0 in 10090: 3
-- 0 in 10000: 4
SELECT
(LENGTH(number) - LENGTH(REPLACE(number, '0', ''))) AS char_count
FROM dual;
A better and safer solution is to use the CHAR_LENGTH function instead of the LENGTH function. With CHAR_LENGTH function you can also count multi-byte characters (like §).
Solution using CHAR_LENGTH
-- § in 100§0: 1
SELECT
(CHAR_LENGTH(number) - CHAR_LENGTH(REPLACE(number, '§', ''))) AS char_count
FROM dual;
You can also extend the above solution to count for a string value using multiple characters.
-- 12 in 10120012: 2
SELECT number,
FLOOR((CHAR_LENGTH(number) - CHAR_LENGTH(REPLACE(number, '12', ''))) / CHAR_LENGTH('12')) AS str_count
FROM dual;
demo on dbfiddle.uk
On MySQL you can create a function to use the above logic on a simpler way:
CREATE FUNCTION GetStringCount(strValue VARCHAR(255), strSearchValue VARCHAR(255))
RETURNS INT DETERMINISTIC NO SQL
RETURN FLOOR((CHAR_LENGTH(strValue) - CHAR_LENGTH(REPLACE(strValue, strSearchValue, ''))) / CHAR_LENGTH(strSearchValue));
You can use this new function GetStringCount like this:
-- example to count non-multi-byte character (here 0).
-- 0 in 10090: 3
-- 0 in 10000: 4
SELECT number, GetStringCount(number, '0') AS strCount
FROM dual;
-- example to count multi-byte character (here §).
-- § in 100§0: 1
SELECT number, GetStringCount(number, '§') AS strCount
FROM dual;
-- example to count a string with multiple characters.
-- 12 in 10120012: 2
SELECT number, GetStringCount(number, '12') AS strCount
FROM dual;
I think the first thing to be done is, casting those integer values to string.
https://dev.mysql.com/doc/refman/5.7/en/cast-functions.html#function_cast
Then find occurences of a certain char
https://lists.mysql.com/mysql/215049
mysql> create table numbers(x int);
Query OK, 0 rows affected (0,38 sec)
mysql> select * from numbers;
+-----------+
| x |
+-----------+
| 123000 |
| 1300 |
| 135600 |
| 135623400 |
| 13560 |
| 135160 |
| 13514560 |
| 1351120 |
| 13512310 |
+-----------+
9 rows in set (0,00 sec)
Find occurences of zero
mysql> select x, round((length(cast(x as char(11))) - length( replace( cast( x as char(11) ), "0", "" ) ))/length("0")) as str_x from numbers limit 5;
+-----------+-------+
| x | str_x |
+-----------+-------+
| 123000 | 3 |
| 1300 | 2 |
| 135600 | 2 |
| 135623400 | 2 |
| 13560 | 1 |
+-----------+-------+
5 rows in set (0,00 sec)
Find thirteens
mysql> select x, round((length(cast(x as char(11))) - length( replace( cast( x as char(11) ), "13", "" ) ))/length("13")) as str_x from numbers;
+-----------+-------+
| x | str_x |
+-----------+-------+
| 123000 | 0 |
| 1300 | 1 |
| 135600 | 1 |
| 135623400 | 1 |
| 13560 | 1 |
| 135160 | 1 |
| 13514560 | 1 |
| 1351120 | 1 |
| 13512310 | 1 |
| 132134534 | 2 |
+-----------+-------+
10 rows in set (0,00 sec)
mysql>

How to correctly string token in MySQL

I realize we can use substring() and locate() function for tokonization
I was tried query
insert into sum_of_counts
select substring(pair,1,locate('|',pair)),
sum(count)
from em
group by substring(pair,1,locate('|',pair))
for example : we use 'resumption|||resumption' as pair to query after substring('resumption|||resumption',1,locate('|','resumption|||resumption'))
it should be resumption|
but after the query it appeared
+------------+------+
| wild_pair | sum |
+------------+------+
| resumption | 8 |
+------------+------+
the problem is we could find 'resumption|||resumption' in em table
after I check the table sum_of_counts some of wild_pair are word| some of wild_pair are just word how can I solve this problem?
SELECT
LEFT(`pair`, LOCATE('|||', `pair`)) `wild_pair`,
SUM(count) `sum`
FROM `em`
GROUP BY `wild_pair`;
Should do the same thing easier.
If the error occurs when inserting the result into another table, check if the existing columns are wide enough to take the calculated data in full length.
Your result should not be possible:
mysql> select locate('|', 'resumption|||resumption');
+----------------------------------------+
| locate('|', 'resumption|||resumption') |
+----------------------------------------+
| 11 |
+----------------------------------------+
1 row in set (0.00 sec)
mysql> select substring('resumption|||resumption', 1, 11);
+---------------------------------------------+
| substring('resumption|||resumption', 1, 11) |
+---------------------------------------------+
| resumption| |
+---------------------------------------------+
1 row in set (0.00 sec)
Are you sure that pair is always foo|||bar with 3 |||?

Which is faster: SELECT DISTINCT or WHERE foo != 0?

id | foo | bar
--------------
0 | 0 | ...
1 | 1 | ...
2 | 2 | ...
3 | 0 | ...
4 | 2 | ...
I need all unique foo values, but not "0" which is in very often.
Which is faster?
SELECT foo FROM `table` WHERE foo != 0
or
SELECT DISTINCT foo FROM `table`
The last would keep the 0 but be removed in PHP.
On my server both were fast enough but one of these two option might be theoretically faster :)
Here's an indexed data set of 130,000 rows. The sparse column has values in the range 0-100000. The dense column has values in the range 0-100.
SELECT * FROM my_table;
+----+--------+-------+
| id | sparse | dense |
+----+--------+-------+
| 1 | 0 | 0 |
| 2 | 52863 | 87 |
| 3 | 76503 | 21 |
| 4 | 77783 | 25 |
| 6 | 89359 | 73 |
| 7 | 97772 | 69 |
| 8 | 53429 | 59 |
| 9 | 35206 | 99 |
| 13 | 88062 | 44 |
| 14 | 56312 | 49 |
...
SELECT * FROM my_table WHERE sparse <> 0;
130941 rows in set (0.09 sec)
SELECT * FROM my_table WHERE dense <> 0;
130289 rows in set (0.09 sec)
SELECT DISTINCT sparse FROM my_table;
72844 rows in set (0.27 sec)
SELECT DISTINCT dense FROM my_table;
101 rows in set (0.00 sec)
As you can see, whether or not DISTINCT is faster depends very much on the density of the data.
Obviously, in this instance, the two queries are very different from each other!
As per the condition given in question, distinct will be expensive as it does sorting on all the records in a block fetched in main memory before eliminating the duplicate records while the select with where condition is going to iterate each record in the block only once to filter out the records.
Also the best known sorting algorithm does it in O(nlogn) while iterative record check happen in O(n) time.
Thus, first query is faster here.
Hope, it answers your question.
In my most cases, SELECT foo FROM table WHERE foo != 0 is faster.
But in your case, it can be even faster:
SELECT foo FROM `table` WHERE foo > 0
From the data you've shown, you do not have negative values, so you don't need to check for any. (as pointed out here - MySQL docs - scroll to the comments section)
From the MySQL Distinct docs:
In most cases, a DISTINCT clause can be considered as a special case of GROUP BY
So, if performance is an issue and you don't really need it, don't use it.
SELECT DISTINCT foo FROM `table`
because there is no Where condition

Changing the fractions in sql

I have fractions as string in my database and it is currently like this:
3/8
I want to change to this:
<sup>3</sup>⁄<sub>8</sub>
I have many fractions like this. How do I change them at one shot in SQL? I know I need to use Regular Expressions but not sure how to use it.
What I have tried so far:
UPDATE question_table
SET `option` = Replace(`option`, ?? ,??)
WHERE `option` LIKE '%/%'
Not sure what to fill up in ??.
SELECT * FROM strings;
+--------+
| string |
+--------+
| 19/32 |
| 3/8 |
| 5/16 |
+--------+
SELECT *
, CONCAT('<sup>'
, SUBSTRING_INDEX(string,'/',1)
, '</sup>⁄<sub>'
, SUBSTRING_INDEX(string,'/',-1)
,'</sub>'
) x
FROM strings;
+--------+-----------------------------------+
| string | x |
+--------+-----------------------------------+
| 19/32 | <sup>19</sup>⁄<sub>32</sub> |
| 3/8 | <sup>3</sup>⁄<sub>8</sub> |
| 5/16 | <sup>5</sup>⁄<sub>16</sub> |
+--------+-----------------------------------+
UPDATE strings
SET string = CONCAT('<sup>'
, SUBSTRING_INDEX(string,'/',1)
, '</sup>⁄<sub>'
, SUBSTRING_INDEX(string,'/',-1)
, '</sub>'
);
Query OK, 3 rows affected (0.00 sec)
Rows matched: 3 Changed: 3 Warnings: 0
SELECT * FROM strings;
+-----------------------------------+
| string |
+-----------------------------------+
| <sup>19</sup>⁄<sub>32</sub> |
| <sup>3</sup>⁄<sub>8</sub> |
| <sup>5</sup>⁄<sub>16</sub> |
+-----------------------------------+

SQL (mysql) - If a given row on a given column as a certain value, don't list that column

I have a query that retrieves some data, among those data I have some that are returned with a value like 0. I would like the query to NOT return the columns when that's the case.
How can we do such a thing?
Regards,
MEM
select <column_name> from <table_name> where <column_name> <> 0.0
Here is all the data in a sample database. Notice how there are 3 rows with one having a zero value for the num column.
mysql> select * from test_tbl;
+------+----------+
| num | some_str |
+------+----------+
| 0 | matt |
| 2 | todd |
| 3 | Paul |
+------+----------+
3 rows in set (0.00 sec)
Now lets use the where clause to specify the rows we want to ignore (it's a little bit of reverse logic because we are actually specifying what rows we want).
mysql> select * from test_tbl where num <> 0.0;
+------+----------+
| num | some_str |
+------+----------+
| 2 | todd |
| 3 | Paul |
+------+----------+
2 rows in set (0.00 sec)
Note: This will only work without getting messy if 0 is the only value you are worried about. A better way would be to allow nulls in your column and then you can check to see if they are non-null in the where clause.