MySQL, Search for data containing hex character - mysql

I've got a table my_table with a varchar column col1. utf8
If I was looking for all rows containing the letter a in col1 (balloon, aardvark, etc) then I'd do:
select col1
from my_table
where col1 like "%a%" -- But how search for special hex character?
But what should I put instead of "%a%" if I'm looking for a special hex character, in this case 0xFFFC?
(This is the character: http://www.fileformat.info/info/unicode/char/fffc/index.htm)
Note that I am looking for a way to specify this character in the WHERE clause. I've seen this https://dev.mysql.com/doc/refman/5.7/en/hexadecimal-literals.html as well as Stackoverflow questions/answers that also use hex characters in the Select part. I need it in the WHERE clause. I have seen this How to find certain Hex values and Char() Values in a MySQL SELECT but that uses char(128), but I haven't got an equivalent char number in my case.

use: 0x61 == 'a'
select col1
from my_table
where col1 LIKE concat('%',0x61,'%');
Her is a Sample
CREATE TABLE `tmptable` (
`image` varchar(250) DEFAULT NULL,
UNIQUE KEY `d` (`image`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8;
INSERT INTO `tmptable` (`image`)
VALUES
('äöüß');
> SELECT image,hex(image) FROM tmptable WHERE image LIKE concat ('%',0xC39F,'%');
+--------------+--------------------------+
| image | hex(image) |
+--------------+--------------------------+
| äöüß`´' | C3A4C3B6C3BCC39F60C2B427 |
+--------------+--------------------------+
1 row in set (0.00 sec)

You can write your 'select' as this:
select col1
from my_table
where col1 LIKE CONCAT('%',X'FFFC','%');
You can read how use hexadecimal, as you say, in documentation https://dev.mysql.com/doc/refman/5.7/en/hexadecimal-literals.html
and using concat you use the character resolved.

Related

how to make default text column where comparision binary (case sensitive and trim)

Sorry if this is duplicated, but I don't know how to find about the question.
Hi, this my table:
CREATE TABLE `log_Valor` (
`idLog_Valor` int(11) NOT NULL AUTO_INCREMENT,
`Valor` text binary NOT NULL,
PRIMARY KEY (`idLog_Valor`)
)
ENGINE=InnoDB;
INSERT INTO `log_Valor` (Valor) VALUES ('teste');
INSERT INTO `log_Valor` (Valor) VALUES ('teste ');
I have 2 rows:
1 | 'teste'
2 | 'teste '
When I run:
SELECT * FROM log_Valor where valor = 'teste'
It returns the two rows.
How do I make default comparison case sensitive and to not trim without having to specify in the query BINARY?
Use LIKE instead of =.
SELECT * FROM log_Valor WHERE valor LIKE 'teste';
From the documentation
In particular, trailing spaces are significant, which is not true for CHAR or VARCHAR comparisons performed with the = operator
DEMO

MySQL LIKE matching at the end of the string

I'm trying to figure out why these two like statements are evaluated equally. In the first, I'm doing a simple select which returns 22 rows. In the second, I'm expecting that my update / replace should also return 22 rows affected. Can anybody see what I'm doing wrong? These should match strings like "I got a knee mri".
SET #acro = 'mri';
SELECT title FROM mytable WHERE title LIKE concat('% ', #acro);
//returns n rows
UPDATE mytable
SET title = REPLACE(title, CONCAT(' ', #acro), CONCAT(' ', UPPER(#acro)))
WHERE title LIKE CONCAT('% ', #acro);
//returns 0 rows
CREATE TABLE `mytable` (
`id` int(11) unsigned NOT NULL AUTO_INCREMENT,
`title` text,
`author` varchar(50) DEFAULT NULL,
PRIMARY KEY (`id`)
) ENGINE=InnoDB AUTO_INCREMENT=119232 DEFAULT CHARSET=utf8;
The "rows affected" count is the number of rows that were modified, not the number of rows that were matched.
One explanation is that the column title is using a case insensitive collation, that is, a characterset that has a name ending in _ci.
It's possible that 22 rows were "matched", but no rows needed to be modified.
If the column is defined with characterset/collation latin1_swedish_ci, you could try comparing the results from a query like this:
SET #acro = _latin1'mri';
SELECT title
FROM mytable
WHERE title COLLATE latin1_general_cs LIKE UPPER(CONCAT('% ', #acro));
^^^
Ah, here's the answer: MySQL Update query with LIKE in WHERE clause not affecting matching rows
Replace() is case sensitive but like is not.

MySQL Order By doesn't work on Concat(enum)

Currently we have an interessting problem regarding the sort order of MySQL in an enum-field. The fields enum entries have been sorted in the order we want it. Just to be save, we added a CONCAT around it, so it would be cast to char and ordered in alphabetical order, just as suggested by the MySQL-reference (MySQL Reference - Enum)
Make sure that the column is sorted lexically rather than by index number by coding ORDER BY CAST(col AS CHAR) or ORDER BY CONCAT(col).
But that didn't produce the expected results, so we started to investigate further. It seems that the order by statement doesn't work on a combination of enum and the concat function. I've wrote the following sample script, which should show my point:
CREATE TABLE test (
`col1` enum('a','b','c') COLLATE utf8_bin DEFAULT NULL
) ENGINE=MyISAM DEFAULT CHARSET=utf8 COLLATE=utf8_bin;
INSERT INTO test
VALUES ('b'), ('c'), ('a');
SELECT * FROM test; -- b, c, a
SELECT * FROM test ORDER BY col1 ASC; -- a, b, c
SELECT * FROM test ORDER BY CAST(col1 AS CHAR) ASC; -- a, b, c
SELECT * FROM test ORDER BY CAST(col1 AS BINARY) ASC; -- a, b, c
SELECT * FROM test ORDER BY CONCAT(col1) ASC; -- b, c, a - This goes wrong
I am currently suspecting some kind of problem with the collation/encoding, but I'm not sure. My databases default encoding is also utf8. The MySQL version is 5.6.12 but it seems to be reproduceable with MySQL 5.1. The storage engine is MyIsam but it also occurs with the memory engine.
Any help would be appreciated.
Update:
As it seems the problem is produced only in MySQL 5.6 and by the collation of the column. With the first CREATE TABLE statement, the queries work fine.
CREATE TABLE test (
`col1` enum('a','b','c') COLLATE utf8_general_ci DEFAULT NULL
)
With the second they don't.
CREATE TABLE test (
`col1` enum('a','b','c') COLLATE utf8_bin DEFAULT NULL
)
The collation of the table and/or database don't seem to affect the queries. The queries can be tested in this SQL Fiddle
Strange,it works in this fiddle.Do you have a trigger or something?
http://sqlfiddle.com/#!2/0976a/2
BUT,in 5.6 goes haywire:
http://sqlfiddle.com/#!9/0976a/1
Mysql bug,probably.
More,if you input the values in the enum in the "proper" order it works:
http://sqlfiddle.com/#!9/a3784/1
IN the doc:
ENUM values are sorted based on their index numbers, which depend on
the order in which the enumeration members were listed in the column
specification. For example, 'b' sorts before 'a' for ENUM('b', 'a').
As per the document:
Under the Handling of Enumeration Literals section, it states that:
If you store a number into an ENUM column, the number is treated as
the index into the possible values, and the value stored is the
enumeration member with that index. (However, this does not work with
LOAD DATA, which treats all input as strings.) If the numeric value is
quoted, it is still interpreted as an index if there is no matching
string in the list of enumeration values. For these reasons, it is not
advisable to define an ENUM column with enumeration values that look
like numbers, because this can easily become confusing.
For example, the following column has enumeration members with string values of '0', '1', and '2', but numeric index values of 1, 2, and 3:
numbers ENUM('0','1','2')
If you store 2, it is interpreted as an
index value, and becomes '1' (the value with index 2). If you store
'2', it matches an enumeration value, so it is stored as '2'. If you
store '3', it does not match any enumeration value, so it is treated
as an index and becomes '2' (the value with index 3).
mysql> INSERT INTO t (numbers) VALUES(2),('2'),('3');
mysql> SELECT * FROM t;
+---------+
| numbers |
+---------+
| 1 |
| 2 |
| 2 |
+---------+
In your case:
INSERT INTO test
VALUES ('2'), ('3'), ('1');
Index value of '2' is 2, '3' is 3 and '1' is 1.
So the output is 2,3,1

MySQL SELECT against varbinary column

This is a follow up to a previous issue I had posted here.
I created a test table:
CREATE TABLE `my_test_table` (
`record_id` INT(11) UNSIGNED NOT NULL AUTO_INCREMENT,
`col1` BINARY(20) NULL DEFAULT NULL,
`col2` CHAR(40) NULL DEFAULT NULL,
PRIMARY KEY (`record_id`)
)
Then ran the statement:
INSERT INTO my_test_table (col1, col2) VALUES(sha1('test'), sha1('test') );
The data looks like...
1 0x6139346138666535636362313962613631633463 a94a8fe5ccb19ba61c4c0873d391e987982fbbd3
I'm not sure how I can select against the VARBINARY column. I can select against the CHAR like:
SELECT * FROM my_test_table WHERE col2 = sha1('test');
I've tried
SELECT * FROM my_test_table WHERE col1 = hex(sha1('test'));
And other variations but can't seem to find a solution (if there is one). I need to be able to check to see if a value already exists in the database before I allow a new insert. I was looking at VARBINARY and BINARY based on previous suggestions. Thanks.
I have not read your previous question, but based on the source code in this question, you are only storing the first 20 characters of the sha1 hash in col1, so if you want to select it you should just look for the first 20 characters of the sha1 hash.
For example:
SELECT *
FROM my_test_table
WHERE col1 = left(sha1('test'),20);
Data truncation: Data too long for column 'col1' at row 1: INSERT INTO my_test_table (col1, col2) VALUES(sha1('test'), sha1('test') )
Can this be the reason why you cannot select the data properly?
BTW the sha1('test') returns a STRING of hex characters...
You should use unhex(sha1('test')) when inputing data as a hex string, or else it wont be entered as acsii values which wont work with matching at all
SELECT * FROM my_test_table WHERE col1 = unhex(sha1('test'));
should be the matching query also.

String compare exact in query MySQL

I created table like that in MySQL:
DROP TABLE IF EXISTS `barcode`;
CREATE TABLE `barcode` (
`id` int(11) NOT NULL AUTO_INCREMENT,
`code` varchar(40) COLLATE utf8_bin DEFAULT NULL,
PRIMARY KEY (`id`)
) ENGINE=InnoDB AUTO_INCREMENT=3 DEFAULT CHARSET=utf8 COLLATE=utf8_bin;
INSERT INTO `barcode` VALUES ('1', 'abc');
INSERT INTO `barcode` VALUES ('2', 'abc ');
Then I query data from table barcode:
SELECT * FROM barcode WHERE `code` = 'abc ';
The result is:
+-----+-------+
| id | code |
+-----+-------+
| 1 | abc |
+-----+-------+
| 2 | abc |
+-----+-------+
But I want the result set is only 1 record. I workaround with:
SELECT * FROM barcode WHERE `code` = binary 'abc ';
The result is 1 record. But I'm using NHibernate with MySQL for generating query from mapping table. So that how to resolve this case?
There is no other fix for it. Either you specify a single comparison as being binary or you set the whole database connection to binary. (doing SET NAMES binary, which may have other side effects!)
Basically, that 'lazy' comparison is a feature of MySQL which is hard coded. To disable it (on demand!), you can use a binary compare, what you apparently already do. This is not a 'workaround' but the real fix.
from the MySQL Manual:
All MySQL collations are of type PADSPACE. This means that all CHAR and VARCHAR values in MySQL are compared without regard to any trailing spaces
Of course there are plenty of other possiblities to achieve the same result from a user's perspective, i.e.:
WHERE field = 'abc ' AND CHAR_LENGTH(field) = CHAR_LENGTH('abc ')
WHERE field REGEXP 'abc[[:space:]]'
The problem with these is that they effectively disable fast index lookups, so your query always results in a full table scan. With huge datasets that makes a big difference.
Again: PADSPACE is default for MySQLs [VAR]CHAR comparison. You can (and should) disable it by using BINARY. This is the indended way of doing this.
You can try with a regular expression matching :
SELECT * FROM barcode WHERE `code` REGEXP 'abc[[:space:]]'
i was just working on case just like that when using LIKE with wildcard (%) resulting in an unexpected result. While searching i also found STRCMP(text1, text2) under string comparison feature of mysql which compares two string. however using BINARY with LIKE solved the problem for me.
SELECT * FROM barcode WHERE `code` LIKE BINARY 'abc ';
You could do this:
SELECT * FROM barcode WHERE `code` = 'abc '
AND CHAR_LENGTH(`code`)=CHAR_LENGTH('abc ');
I am assuming you only want one result, you could use LIMIT
SELECT * FROM barcode WHERE `code` = 'abc ' LIMIT 1;
To do exact string matching you could use Collation
SELECT *
FROM barcode
WHERE code COLLATE utf8_bin = 'abc';
The sentence right after the one quoted by Kaii basically says "use LIKE" :
“Comparison” in this context does not include the LIKE pattern-matching operator, for which trailing spaces are significant
and the example below shows that 'Monty' = 'Monty ' is true, but not 'Monty' LIKE 'Monty '.
However, if you use LIKE, beware of literal strings containing the '%', '_' or '\' characters : '%' and '_' are wildcard characters, '\' is used to escape sequences.