If I use Sql BETWEEN operator with Hexa numbers as Strings, will i get the same result as converting the hexa in to numeric and then performing between operation.
Will the below two sql's get same results.
Product ID is stored in db as hexa string
SELECT product_name FROM Products WHERE product_id BETWEEN "24ab" AND "82df" ORDER BY product_id;
Product ID is converted from hexa to decimal (int) in DB.
SELECT product_name FROM Products WHERE product_id BETWEEN 9387 AND 33503 ORDER BY product_id;
My expectation is above two sql's will output same products.
Example of sql BETWEEN operation on strings can be found here.
hexa(24ab) = decimal(9837) and
hexa(82df) = decimal(33503)
Just curious - does string comparison use ascii value of each char to compare. I hope so.
You're on the right track, but it's more accurate to say that string comparison compares character-by-character, according to the collation defined for the expression. This allows for characters to compare as the same if it's appropriate, according to national rules for string comparison. Not all the world is ASCII, in other words.
For purposes of hexadecimal strings, these include only characters that are ASCII, so we can simplify and say yes, the strings are compared by their ASCII values.
Where some people find trouble is that the hex strings are of different lengths. For example, is FF great than 24AB?
mysql> select 'ff' > '24ab';
+---------------+
| 'ff' > '24ab' |
+---------------+
| 1 |
+---------------+
To use hex strings in inequality comparisons (including BETWEEN), you should make sure the strings have equal length, and if not, then zero-pad the shorter strings.
mysql> select '00ff' > '24ab';
+-----------------+
| '00ff' > '24ab' |
+-----------------+
| 0 |
+-----------------+
Related
Hi I have a table which has a column with a char(32) datatype, I need to convert this to a BINARY(16) datatype. I have tried just altering the column type but that removes all the data in the column.
The following code is how I updated the datatype of the column. This resulted in me losing all the data in the column.
ALTER TABLE table_name MODIFY device_uuid BINARY(16)
Is there a way to change the datatype of the column and convert all the data to the new datatype without losing any data.
The reason I am doing it is because I am trying to retrieve some lost data which is located in this table. The table I need to import the data to is exactly the same but the column type is BINARY(16) not CHAR(32).
Thank you in advance if you are able to help with this.
It sounds like you want to have a UUID represented as a string of hexadecimal digits. These normally have four dashes in them so the length is actually 36 characters. But if you remove the dashes, it can be 32 characters.
mysql> SELECT UUID();
+--------------------------------------+
| UUID() |
+--------------------------------------+
| b4d841ec-5220-11e9-901f-a921a9eb9f5b |
+--------------------------------------+
mysql> SELECT REPLACE(UUID(), '-', '');
+----------------------------------+
| REPLACE(UUID(), '-', '') |
+----------------------------------+
| d3dbd450522011e9901fa921a9eb9f5b |
+----------------------------------+
But in a hex string, each two characters represent data that could be encoded in one byte of binary data. For example, FF is the hex value for 255, which is the maximum value of one byte. Therefore hex strings take twice as many bytes as the equivalent data in binary. If space is constrained, you might want to convert your UUID values to binary so you can store them in half the space.
You can do this with the UNHEX() function.
mysql> SELECT UNHEX(REPLACE(UUID(), '-', ''));
+---------------------------------+
| UNHEX(REPLACE(UUID(), '-', '')) |
+---------------------------------+
| $S,vR!??!??[ |
+---------------------------------+
Binary data isn't pleasant to display or type in human-oriented interfaces, because some bytes correspond to unprintable characters.
But when you did ALTER TABLE table_name MODIFY device_uuid BINARY(16), you didn't decode the hex strings with UNHEX(). At best, this caused the first 16 bytes of ASCII hexadecimal characters to be mapped to the 16 bytes of your BINARY(16) column, and it truncated the string at that point. It's as if you did this to every row:
mysql> SELECT LEFT(REPLACE(UUID(), '-', ''), 16);
+------------------------------------+
| LEFT(REPLACE(UUID(), '-', ''), 16) |
+------------------------------------+
| 364e6db8522211e9 |
+------------------------------------+
The first 16 bytes are still hexadecimal digits. The bytes are ASCII values for those digits, not the binary equivalent of each pair of digits. The latter 16 bytes of every string were truncated, and not stored. If that data was important, I hope you have a backup of your database, because restoring that backup is now the only way you can recover that data.
What you should have done is the following:
ALTER TABLE table_name ADD COLUMN device_uuid_bin BINARY(16);
UPDATE table_name SET device_uuid_bin = UNHEX(device_uuid);
...check the data to make sure the conversion worked...
...test any applications work with the binary data...
ALTER TABLE table_name DROP COLUMN device_uuid;
If you take the algorithm given by Karwin, and shuffle the bits some, you get a time-ordered UUID. This is often much better for performance because of being semi-ordered rather than "random".
I discuss that in my blog here. It points out that the equivalent code has been provided in standard functions in MySQL 8.0.
Also, note that this 'trick' applies only to "Type 1" uuids, which is what MySQL/MariaDB uses.
I have a table with the following format.
|id | int_col|
--------------
1 | 0 |
2 | 0 |
--------------
The DDL is defined below:
id - is the primary key - it is also set to auto increment
int_col - is an attribute
I tried the below queries:
Select * from table_name where id='string_value';
Returns 0 rows.
Select * from table_name where int_col = 'string_value';
Returns all rows
I am not sure as to why it has returned all rows. I expected it to return 0 rows for both queries.
To make it short: do not compare strings and integers in MySQL. This can lead to unpredictable results such as those you are seeing.
As per MySQL conversion rules, comparing a string and an integer actually results in both values being under the hood converted to floating point numbers, and then compared. The documentation warns :
Comparisons that use floating-point numbers [...] are approximate because such numbers are inexact. This might lead to results that appear inconsistent.
Further in the doc, another disclaimers can be found that specifically relates to integer/string comparison :
Furthermore, the conversion from string to floating-point and from integer to floating-point do not necessarily occur the same way. The integer may be converted to floating-point by the CPU, whereas the string is converted digit by digit in an operation that involves floating-point multiplications.
The results shown will vary on different systems, and can be affected by factors such as computer architecture or the compiler version or optimization level.
Finally, here is an example of (possible) conversion discrepancy, also from MySQL documentation:
mysql> SELECT '18015376320243458' = 18015376320243458;
-> 1
mysql> SELECT '18015376320243459' = 18015376320243459;
-> 0
I need to clean up a database where one of the columns (TOTAL_AREA) has some characters on some of the entries (not all of them)
Such as 5000㎡
I need to clean all the fields that have this entry to show only 500
How can I do it with SQL? I looked at TRIM but couldn't find a way to select all entries that have a character after the number and them TRIM it
Any help would be appreciated
Thanks
This is pretty easy. MySQL does implicit conversion, ignoring characters after the digits. So, you can do:
select (col * 1.0 / 10)
For your example, this will return 500.
Assuming you want to get rid of all characters that are not digits, you can use e.g. REGEXP_REPLACE, e.g.
create or replace table x(s string);
insert into x values
('111'),
('abc234xyz'),
('5000㎡'),
('9000㎡以上');
select s, regexp_replace(s, '[^\\d]*(\\d+)[^\\d]*', '\\1') from x;
-----------+--------------------------------------------------+
S | REGEXP_REPLACE(S, '[^\\D]*(\\D+)[^\\D]*', '\\1') |
-----------+--------------------------------------------------+
111 | 111 |
abc234xyz | 234 |
5000㎡ | 5000 |
9000㎡以上 | 9000 |
-----------+--------------------------------------------------+
What we do there is we match sequences of 0-or-more non-digit characters, followed by 1-or-more digit characters, and again 0-or-more non-digit characters, and product only the middle sequence.
Note, that you can use a different regexp depending what characters exactly you want to keep/remove.
I'm using psql (9.1.3). I have a table (say) A
A has two columns:
a_id : Integer
customer_pay : double precision
I have these values in the table.
a_id | customer_pay |
--------------------+--------------+
1733684 | -264.6 |
1723382 | -314.84 |
1728106 | 50.55 |
1741636 | -264.6 | (4 rows)
but when I did
select a_id from A where customer_pay = -264.6;
I got nothing.
I tried all possible precision variaations like -264.60, -264.00, etc.
This query works accurately for +264.6.
What should I do to select values with negative double precision type.
thaks for the help.
select a_id
from a
where round(customer_pay::numeric, 2) = -264.6
From the manual:
Calculations with numeric values yield exact results where possible, e.g. addition, subtraction, multiplication. However, calculations on numeric values are very slow compared to the integer types, or to the floating-point types described in the next section.
The data type DOUBLE PRECISION is an approximate, inexact data type. I see no reason, someone would ever use it instead of an exact type such as DECIMAL.
With approximate data types, no matter what language, you should never use =. When comparing an inexact data value, always allow for some delta, e.g. where customer_pay between -264.6000001 and 264.5999999. This alone should explain why I'd never use them ;-)
Any idea why this works sensibly*:
mysql> select lower('AB100c');
+-----------------+
| lower('AB100c') |
+-----------------+
| ab100c |
+-----------------+
1 row in set (0.00 sec)
But this doesn't?
mysql> select lower(concat('A', 'B', 100,'C'));
+----------------------------------+
| lower(concat('A', 'B', 100,'C')) |
+----------------------------------+
| AB100C |
+----------------------------------+
1 row in set (0.00 sec)
*sensibly = 'the way I think it should work.'
As stated on MySql String functions:
LOWER(str)
LOWER() is ineffective when applied to
binary strings (BINARY, VARBINARY,
BLOB).
CONCAT(str1,str2,...)
Returns the string that results from
concatenating the arguments. May have
one or more arguments. If all
arguments are nonbinary strings, the
result is a nonbinary string. If the
arguments include any binary strings,
the result is a binary string. A
numeric argument is converted to its
equivalent binary string form; if you
want to avoid that, you can use an
explicit type cast.
In your code you are passing 100 as a numeric so concat will return a binary string and lower is ineffective when applied to binary strings that's why it's not get converted. If you want to convert you can try this:
select lower(concat('A', 'B', '100','C'));
lower is used to convert STRINGS to lowercase. But your value 100 is considered numeric. If you want to still achieve the result of lower case conversion, you should enclose the number in quotes like this:
select lower(concat('A', 'B', '100','C'));
I've tested this and it works fine.
And here is an other example with CONCAT and LIKE
LOWER(CONCAT(firstname, ' ', lastname)) LIKE LOWER('%my name%')