Equal to operation not working on a field with updated collation - mysql

I was trying to convert an existing varchar column with a unique index on it to a case sensitive column. So to do this, I updated the collation of the particular column.
Previous value: utf8mb4_unicode_ci
Current value: utf8mb4_bin
Now I have a row in my table TEST_TABLE with test_column value is abcd.
When I try to run a simple query like SELECT * FROM TEST_TABLE WHERE test_column = 'abcd'; it returns no result.
However when I try SELECT * FROM TEST_TABLE WHERE test_column LIKE 'abcd'; it returns the data correctly.
Also when I try SELECT * FROM TEST_TABLE WHERE BINARY test_column = 'abcd'; it returns the data correctly.
One more thing I tried was creating a duplicate of the table with column collation set as utf8mb4_bin while creating itself and then copy all data from original table. Then the query SELECT * FROM TEST_TABLE WHERE test_column = 'abcd'; is working alright.
So this seems to be a problem with BINARY conversion. Is there any solution to this or Am I doing something wrong ?

This seems to be an issue with MySQL. The steps I followed to resolve this is as follows:
dropped the unique index on the column
change the collation of the column
created the unique index again
Now it is working as expected. It seems MySQL didn't rebuild unique index when collation was changed. However the above steps solved my issue.

How did you change the collation? There are about 4 ways that you might think to do it. Most do something different.
Probably ALTER TABLE ... CONVERT TO COLLATION utf8mb4_bin was what you needed.
Why "bin"? You want to match case and accents? That is "abcd" != "Abcd"?

Related

Convert MySQL LONGTEXT column to JSON

I have an existing table that holds valid JSON data but is stored as LONGTEXT (character set utf8mb4 with collation utf8mb4_bin). Doing JSON queries on this is highly inefficient and I want to change the data type of this column to JSON.
When I do so in HeidiSQL I get an: 'COLLATION 'utf8mb4_bin' is not valid for CHARACTER SET 'binary'. I can fix this by resetting the collation to empty.
I mention this because I thought the character set for a JSON column is utf8mb4 and it's default collation is utf8mb4_bin. In the JSON are some GUIDs and when I try to query them, it appears that I have to use LIKE. If I use the 'normal' = I get no results.
Works: SELECT * FROM MyTable WHERE Data->>"$.Shop[*].ContactPerson.UserId" LIKE "%b1b9ad95-1098-4e6c-a697-50c2a47dc301%";
Doesn't work: SELECT * FROM MyTable WHERE Data->>"$.Shop[*].ContactPerson.UserId" = "b1b9ad95-1098-4e6c-a697-50c2a47dc301";
Is that a problem with my syntax or is it related to collation (I'd say no, but it's the only discrepancy I find). BTW: Leaving out the % in the LIKE also produces no results.
Create/insert:
CREATE TABLE Temp ( `Data` LONGTEXT COLLATE UTF8MB4_BIN );
INSERT INTO Temp( `Data` ) VALUES ("{\"Shop\":[{\"ContactPerson\": {\"UserId\":\"b1b9ad95-1098-4e6c-a697-50c2a47dc301\"}},{\"ContactPerson\": {\"UserId\":\"B27DA5A7-D678-4513-8A44-BD76CC4651CC\"}}]}");
INSERT INTO Temp( `Data` ) VALUES ("{\"Shop\":[{\"ContactPerson\": {\"UserId\":\"82899A81-2024-4F68-917A-710764296A21\"}},{\"ContactPerson\": {\"UserId\":\"AE59DCA7-32AF-4131-93C7-A1BB698DF8E0\"}}]}");
INSERT INTO Temp( `Data` ) VALUES ("{\"Shop\":[{\"ContactPerson\": {\"UserId\":\"4154477B-1B70-4F25-9E4B-2CFBBF4F678F\"}},{\"ContactPerson\": {\"UserId\":\"B27DA5A7-D678-4513-8A44-BD76CC4651CC\"}}]}");
Trying the update: ALTER TABLE `Temp` MODIFY `Data` JSON;
And now it works... (of course) :(
So apparently when using the table-editor in HeidiSQL it fails (I've retried this). Using a SQL statement actually does what I want.
That still leaves me with having to use the LIKE as opposed to = in my query.
Thank you to #Rick James for the "aha moment": Where clause for JSON field on array of objects
So in my case:
SELECT * FROM `Temp` WHERE JSON_SEARCH(`Data`, 'one', 'b1b9ad95-1098-4e6c-a697-50c2a47dc301', NULL, '$.Shop[*].ContactPerson.UserId') IS NOT NULL;
Update:
Issue was reported and will be fixed in next build (https://github.com/HeidiSQL/HeidiSQL/issues/1652)

CONVERT to CHAR cause index on VARCHAR column doesn't work

SELECT * FROM table1 WHERE a = '1';
SELECT * FROM table1 WHERE a = CONVERT(1, CHAR);
Column a is VARCHAR type, and I have already created an index on it. The first one uses index but the second one doesn't. Any Clue on this?
I suspect that maybe MySQL takes CHAR and VARCHAR as two different types, so I changed column a to CHAR, and the index doesn't work either.
Sounds like a CHARACTER SET or COLLATION problem. Please provide:
SHOW VARIABLES LIKE 'char%';
how you are connecting to the database
SHOW CREATE TABLE table1;
Probably the answer involves changing the CONVERT:
CONVERT(1, CHAR charset utf8)
What is the real query; there may be some other approach that is better for your situation. Using CONVERT is a kludge; let's go to the need for it.
To see the conversion(s), do
EXPLAIN FORMAT=JSON SELECT ...

mysql error 1062 during alter table modify column

I have a table that looks like this:
CREATE TABLE t1 (
id BIGINT AUTO_INCREMENT NOT NULL PRIMARY KEY,
col1 VARCHAR(256),
UNIQUE INDEX t1_col1_index (col1)
)
I'm trying to modify the col1 type using the following query:
ALTER TABLE t1 MODIFY COLUMN col1 varchar(191) COLLATE utf8mb4_unicode_ci;
However, I run into this duplication error:
error: ("1062", "QMYSQL3: Unable to execute statement", "Duplicate entry '+123456789' for key 't1_col1_index'")
I initially thought it could be because two or more rows might 'contain' similar value for col1 and on changing varchar length the data gets truncated but then I found out that data truncation wouldn't even allow the query to go through. Any pointers on what could be causing this?
EDIT (Resolved): Truncation does happen when ##sql_mode is not set with STRICT_TRANS_TABLES. This was causing the error.
You are reducing the length of a varchar column that is controlled by a UNIQUE constraint.
This is risky business. Oversize data will be silently trimed (unless you have the ##sql_mode set to STRICT_TRANS_TABLES in which case an error will be raised). This probably generates duplicates, which cause the error to be raised by your UNIQUE constraint.
You can check the max length of the values in your column with :
SELECT MAX(CHAR_LENGTH(col1)) FROM t1:
I am not sure if this is work.
Try to check the table t1.
select count(1) from t1 where col1 = 123456789
Now if count is greater than one then try to remove the other one and leave only one record.
Then try to run your statement again.
Reminder:
Do back up first before removing.

Inserting datetime value into sql server table column

I'm attempting to insert a datetime('2013-08-30 19:05:00') value into a SQL server database table column(smalldatetime) and the value stays "NULL" after the insert.
I'm doing this to 6 other columns that are the exact same type. What is this only occuring on one column? I've triple checked that the names of the columns are correct. Any ideas?
Assuming the situation is as you describe
CREATE TABLE T
(
S SMALLDATETIME NULL
)
INSERT INTO T
VALUES('2013-08-30 19:05:00')
SELECT *
FROM T /*Returns NULL*/
There are only two ways I can think of that this can happen.
1) That is an ambiguous datetime format. Under the wrong session options this won't cast correctly and if you have some additional options OFF it will return NULL rather than raise an error (e.g.)
SET LANGUAGE Italian;
SET ansi_warnings OFF;
SET arithabort OFF;
INSERT INTO T
VALUES('2013-08-30 19:05:00')
SELECT *
FROM T /*NULL inserted*/
2) You may have missed the column out in an INSTEAD OF trigger, or have an AFTER trigger that actually sets the value back to NULL.

MySQL: char_length(), wrong value for Russian

I am using char_length() to measure the size of "Русский": strangely, instead of telling me that it's 7 chars, it tells me there are 14. Interestingly if the query is simply...
SELECT CHAR_LENGTH('Русский')
...the answer is correct. However if I query the DB instead, the anser is 14:
SELECT CHAR_LENGTH(text) FROM locales WHERE lang = 'ru-RU' AND name = 'lang_name'
Anybody go any ideas what I might be doing wrong? I can confirm that the collation is utf8_general_ci and the table is MyISAM
Thanks,
Adrien
EDIT: My end objective is to be able to measure the lengths of records in a table containing single and double-byte chracters (eg. English & Russian, but not limited to these two languages only)
Because of two bytes is used for each UTF8 char.
See http://dev.mysql.com/doc/refman/5.5/en/string-functions.html#function_char-length
mysql> set names utf8;
mysql> SELECT CHAR_LENGTH('Русский'); result - 7
mysql> SELECT CHAR_LENGTH('test'); result - 4
create table test123 (
text VARCHAR(255) NOT NULL DEFAULT '',
text_text TEXT) Engine=Innodb default charset=UTF8;
insert into test123 VALUES('русский','test русский');
SELECT CHAR_LENGTH(text),CHAR_LENGTH(text_text) from test123; result - 7 and 12
I have tested work with: set names koi8r; create table and so on and got invalid result.
So the solution is recreate table and insert all data after setting set names UTF8.
the function return it's anwser guided by the most adjacent charset avaiable
in the case of a column, the column definition
in the case of a literal, the connection default
review the column charset with:
SELECT CHARACTER_SET_NAME FROM information_schema.`COLUMNS`
where table_name = 'locales'
and column_name = 'text'
be careful, it is not filtered by table_schema