How to retrieve special Char from database? - mysql

I am trying to retrieve a special Greek character µ from a MySQL database but in HTML it is
showing this �.
My HTML charset: content="text/html; charset=windows-1252"
In addition, after it retrieves the character it also need to be able to use the character to compare back in the database.
I've tried putting the HTML code in the database like μ then it is not able to compare back to the database because HTML turns it into µ.
How can I do this appropriately?

First, I would recommend using utf8 as your charset.
Start by switching the default for the database:
ALTER DATABASE db_name CHARACTER SET utf8;
Next, to switch your tables over to utf8 apply this SQL:
ALTER TABLE tbl_name CONVERT TO CHARACTER SET utf8;
which you will have to do for each table.
Finally, and quite unfortunately, you have to know convert all the character data columns that were made under the old charset (varchar, text, etc.). You have to do this by way of first casting to a BLOB so that the characters already stored are not mangled:
alter table tbl_name change col_name col_name LONGBLOB;
alter table tbl_name change col_name col_name LONGTEXT CHARACTER SET utf8;
Wordpress publishes a column type by column type guide on how to do this step: converting database charset columns.
Then, finally update the charset declaration in your xhtml (or without the ending / if it is html):
<meta http-equiv="Content-Type" content="text/html;charset=utf-8" />
This process is arduous, but will convert the database. It is much easier to start a db in utf8.
This is all assuming MySQL 5, for which you can see the Mysql 5 ALTER TABLE reference.

Try this on your table containing the special chars (based off of this post):
ALTER TABLE tbl_name CONVERT TO CHARACTER SET utf8;

See Shelhamer's answer, but you also need to set the db connection to utf8. You can either use mysql_set_charset('utf8'); right after you connect to the DB. Alternatively run the following query after your're connected:
SET character_set_results = 'utf8', character_set_client = 'utf8', character_set_connection = 'utf8', character_set_database = 'utf8', character_set_server = 'utf8';
however, i would still recommend you use htmlentities() when displaying your content on a website to make sure is's all valid HTML. Firefox tends to barf if you mix up the encoding.

in php use utf8_encode() before saving it to the database.
It will solve the problem

Related

MySQL - utf8 characters no displaying correctly on web frontend

I have a database which has the latin1 default characterset - info obtained by running the following statement:
SELECT default_character_set_name FROM information_schema.SCHEMATA
WHERE schema_name = "schemaname";
The default character set for each table and column in this database is set to utf8.
When I look at the data in the tables I can see data is stored as utf8 e.g the currency symbol € is stored in the table as €. Similarly apostraphes are stored as ’ etc.
On the web frontend I have the following meta tag and so the characters render correctly.
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
However I'm also seeing a lot of � symbols on the webpage which I don't see inside the database?
When I change the database connection to include the charset utf8 as follows: mysql:host=myhost;dbname=mydatabase;charset=utf8, the diamond symbols disappear but then all the other utf8
characters revert to exactly how they are saved in the database e.g. the € symbol renders as € on the webpage?
Why is this happening?
How do I fix this and also change character set to utf8mb4?
Any help appreciated.
* UPDATE *
Tried the following steps:
for the database:
ALTER DATABASE database_name CHARACTER SET = utf8mb4 COLLATE = utf8mb4_unicode_ci;
For each table:
ALTER TABLE table_name CONVERT TO CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci;
For each column:
ALTER TABLE table_name CHANGE column_name column_name VARCHAR(191) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci;
Not sure if Step 3 is necessary since when I do SHOW CREATE TABLE after step 2, whilst the definition doesn't display the column charset it does display the default charset for the table as utf8mb4. As a sanity check I did run step 3 on one of the tables columns but it makes no difference - € is being rendered on the page as € with db connection as follows:
`mysql:host=myhost;dbname=mydatabase;charset=utf8mb4`
I had to run the following on each column I wanted converting which seems to fix some issues
UPDATE tbl_profiles SET profile =
convert(cast(convert(profile using latin1) as binary) using UTF8MB4);
but still seeing characters such as Iâm and «Âand ⢠rendered on the webpage
Any ideas?
* UPDATE 2 *
After running steps 1 and 2 above I have a table column as follows:
`job_salary` VARCHAR(150) NULL DEFAULT NULL COLLATE 'utf8mb4_unicode_ci',
The following query on this column returns the following result:
SELECT job_salary FROM tbl_jobs WHERE job_id = 2235;
€30,000 plus excellent benefits
I execute the following statement on this column:
UPDATE tbl_jobs SET job_salary = CONVERT(BINARY(CONVERT(job_salary USING latin1)) USING utf8mb4);
But I get the following error which means some other record has a invalid utf8mb4
Invalid utf8mb4 character string: '\x8010000 to \x8020000 Per: annum'
First, let's discuss the Mojibake of the Euro sign. All of this applies to both utf8 and utf8mb4, since the Euro is encoded the same way and there is.
It is very likely that the data was initially stored incorrectly. If you can get back to the INSERT program, let's check for:
The bytes to be stored need to be UTF-8-encoded. What was the client programming language? Where did the data come from?
The connection when INSERTing and SELECTing text needs to specify utf8 or utf8mb4. Do you have the connection parameters?
The column needs to be declared CHARACTER SET utf8 (or utf8mb4). It sounds like this was always correct.
HTML should start with .
What is currently in the table?
SELECT col, HEX(col) FROM ... WHERE ...
A correctly stored Euro sign (€) should have hex E282AC. (Interpreting that as latin1 yields €.
If instead, you see hex C3A2E2809AC2AC, you have "double encoding", and the display is probably €.
I have identified several possible fixes, but have not yet determined which applies in your case. The likely candidate is
CHARACTER SET utf8mb4 with double-encoding:
To verify it (before fixing it), please do something like:
SELECT col,
CONVERT(BINARY(CONVERT(col USING latin1)) USING utf8mb4),
HEX(
CONVERT(BINARY(CONVERT(col USING latin1)) USING utf8mb4)
)
FROM ...
WHERE ...
Do not apply a fix on top of another fix. I have struggled for a long time to decipher how character set problems occur and what to do to 'fix' a single problem. But when the wrong fix is applied, I am at a loss to unravel the mess.

Error Code: 1267. Illegal mix of collations (latin1_swedish_ci,IMPLICIT) and (utf8_general_ci,COERCIBLE) [duplicate]

I'm getting this strange error while processing a large number of data...
Error Number: 1267
Illegal mix of collations (latin1_swedish_ci,IMPLICIT) and (utf8_general_ci,COERCIBLE) for operation '='
SELECT COUNT(*) as num from keywords WHERE campaignId='12' AND LCASE(keyword)='hello again 昔 ã‹ã‚‰ ã‚ã‚‹ å ´æ‰€'
What can I do to resolve this? Can I escape the string somehow so this error wouldn't occur, or do I need to change my table encoding somehow, and if so, what should I change it to?
SET collation_connection = 'utf8_general_ci';
then for your databases
ALTER DATABASE your_database_name CHARACTER SET utf8 COLLATE utf8_general_ci;
ALTER TABLE your_table_name CONVERT TO CHARACTER SET utf8 COLLATE utf8_general_ci;
MySQL sneaks swedish in there sometimes for no sensible reason.
CONVERT(column1 USING utf8)
Solves my problem. Where column1 is the column which gives me this error.
You should set both your table encoding and connection encoding to UTF-8:
ALTER TABLE keywords CHARACTER SET UTF8; -- run once
and
SET NAMES 'UTF8';
SET CHARACTER SET 'UTF8';
Use following statement for error
be careful about your data take backup if data have in table.
ALTER TABLE your_table_name CONVERT TO CHARACTER SET utf8 COLLATE utf8_general_ci;
In general the best way is to Change the table collation. However I have an old application and are not really able to estimate the outcome whether this has side effects. Therefore I tried somehow to convert the string into some other format that solved the collation problem.
What I found working is to do the string compare by converting the strings into a hexadecimal representation of it's characters. On the database this is done with HEX(column). For PHP you may use this function:
public static function strToHex($string)
{
$hex = '';
for ($i=0; $i<strlen($string); $i++){
$ord = ord($string[$i]);
$hexCode = dechex($ord);
$hex .= substr('0'.$hexCode, -2);
}
return strToUpper($hex);
}
When doing the database query, your original UTF8 string must be converted first into an iso string (e.g. using utf8_decode() in PHP) before using it in the DB. Because of the collation type the database cannot have UTF8 characters inside so the comparism should work event though this changes the original string (converting UTF8 characters that are not existend in the ISO charset result in a ? or these are removed entirely). Just make sure that when you write data into the database, that you use the same UTF8 to ISO conversion.
I had my table originally created with CHARSET=latin1. After table conversion to utf8 some columns were not converted, however that was not really obvious.
You can try to run SHOW CREATE TABLE my_table; and see which column was not converted or just fix incorrect character set on problematic column with query below (change varchar length and CHARSET and COLLATE according to your needs):
ALTER TABLE `my_table` CHANGE `my_column` `my_column` VARCHAR(10) CHARSET utf8
COLLATE utf8_general_ci NULL;
I found that using cast() was the best solution for me:
cast(Format(amount, "Standard") AS CHAR CHARACTER SET utf8) AS Amount
There is also a convert() function. More details on it here
Another resource here
Change the character set of the table to utf8
ALTER TABLE your_table_name CONVERT TO CHARACTER SET utf8
My user account did not have the permissions to alter the database and table, as suggested in this solution.
If, like me, you don't care about the character collation (you are using the '=' operator), you can apply the reverse fix. Run this before your SELECT:
SET collation_connection = 'latin1_swedish_ci';
After making your corrections listed in the top answer, change the default settings of your server.
In your "/etc/my.cnf.d/server.cnf" or where ever it's located add the defaults to the [mysqld] section so it looks like this:
[mysqld]
character-set-server=utf8
collation-server=utf8_general_ci
Source: https://dev.mysql.com/doc/refman/5.7/en/charset-applications.html

Can I convert MySQL database character set from latin1 to utf8 without losing data?

I want to convert my database to store unicode symbols.
Currently the tables have:
latin_swedish_ci collation and latin1 character set
OR
utf8_general_ci collation and utf8 character set
I am not sure how the existing data is encoded, but I suppose it is utf-8 encoded, as I am using Django which I think encodes the data in utf-8 before sending to the database.
My question is:
Can I convert the tables to utf8_unicode_ci collation and utf-8 character set using the following queries without messing up the existing data? (as sugested in this post)
ALTER DATABASE databasename CHARACTER SET utf8 COLLATE utf8_unicode_ci;
ALTER TABLE tablename CONVERT TO CHARACTER SET utf8 COLLATE utf8_unicode_ci;
Considering latin1 is subset of utf-8, I think it sould work. What do you guys think?
Thank you in advance.
P.S: The version of MySQL is: 5.1
Latin1 is not a subset of UTF-8 - ASCII is. Latin1, however, is represented in Unicode.
CONVERT TO should work, as long as the data was stored in the correct encoding in the first place. Django may have used UTF-8 on the database connection, but the database should have re-encoded on the fly.
To check the actual encoding used - Use the mysql command-line tool to execute an SQL query that selects a row that you know contains non-ASCII characters. Then use the mysql HEX() function to check the bytes used. If you see bytes greater than > 0x7f, check that they don't correspond to valid characters in https://en.wikipedia.org/wiki/ISO/IEC_8859-1#Codepage_layout
If you have c396 sitting in a latin1 column, and you want it to mean Ö, then you are half way to "double encoding". Do not use CONVERT TO; that will really get you into "double encoding".
Instead, you need the 2-step ALTER.
ALTER TABLE Tbl MODIFY COLUMN col VARBINARY(...) ...;
ALTER TABLE Tbl MODIFY COLUMN col VARCHAR(...) ... CHARACTER SET utf8 ...;
If you have already messed it up further, and now the Ö is hex C383E28093, then you need to fix double encoding.
This gets you the latin1 byte in 2 steps:
CONVERT(CONVERT(UNHEX('C383E28093') USING utf8) USING latin1) --> 'Ö' (C396)
HEX(CONVERT(CONVERT(UNHEX('C396') USING utf8) USING latin1)) --> 'Ö' in latin1 (D6)
This gets you the 2-byte utf8 encoding:
CONVERT(BINARY(CONVERT(CONVERT(UNHEX('C383E28093') USING utf8) USING latin1)) USING utf8)
Do you want the column to be latin1? Or utf8?

Problems with charset in PHP/MySQL

I've some problems with special characters in PHP/MySQL (I don't know which one).
Then, I've data stored in a database,using php. I ensured before storing data to add this code:
header('Content-type:text/html; charset=utf-8');
$link=mysqli_connect("host","user","","db") or die(mysqli_error($link));
mysqli_query($link,"SET character_set_results = 'utf8', character_set_client = 'utf8', character_set_connection = 'utf8', character_set_database = 'utf8', character_set_server = 'utf8';SET NAMES utf8");
I also ensured Apache uses the correct charset:
AddDefaultCharset utf-8
In addition I also tried to add on every html page the meta tag:
<meta http-equiv="content-type" content="text/html" charset="UTF-8">
Further, I saved all my php and html files in UTF-8 format.
I noticed that if I write a character like ò in a page and display that page it is correctly displayed. If I get a string query from a database containing ò, it doesn't display correctly, but if I change the code to:
header('Content-type:text/html; charset=iso-8859-1');
the query retrieved from the DB is correctly displayed, a normal writing not.
So,the problem is on mysql charset? How could it be if I setted it with the previous instructions?
try to change your column where you store this date to utf8 also
here some codes you may use.
Change the character-set/collation (database):
ALTER DATABASE db_name DEFAULT CHARACTER SET utf8;
Change the character-set/collation (table):
ALTER TABLE tbl_name DEFAULT CHARACTER SET utf8;
Change the character-set/collation (columns):
ALTER TABLE tbl_name CONVERT TO CHARACTER SET utf8;
Try using http://fi2.php.net/mysqli_set_charset function instead of the mysqli_query() you are using now.

Illegal mix of collations MySQL Error

I'm getting this strange error while processing a large number of data...
Error Number: 1267
Illegal mix of collations (latin1_swedish_ci,IMPLICIT) and (utf8_general_ci,COERCIBLE) for operation '='
SELECT COUNT(*) as num from keywords WHERE campaignId='12' AND LCASE(keyword)='hello again 昔 ã‹ã‚‰ ã‚ã‚‹ å ´æ‰€'
What can I do to resolve this? Can I escape the string somehow so this error wouldn't occur, or do I need to change my table encoding somehow, and if so, what should I change it to?
SET collation_connection = 'utf8_general_ci';
then for your databases
ALTER DATABASE your_database_name CHARACTER SET utf8 COLLATE utf8_general_ci;
ALTER TABLE your_table_name CONVERT TO CHARACTER SET utf8 COLLATE utf8_general_ci;
MySQL sneaks swedish in there sometimes for no sensible reason.
CONVERT(column1 USING utf8)
Solves my problem. Where column1 is the column which gives me this error.
You should set both your table encoding and connection encoding to UTF-8:
ALTER TABLE keywords CHARACTER SET UTF8; -- run once
and
SET NAMES 'UTF8';
SET CHARACTER SET 'UTF8';
Use following statement for error
be careful about your data take backup if data have in table.
ALTER TABLE your_table_name CONVERT TO CHARACTER SET utf8 COLLATE utf8_general_ci;
In general the best way is to Change the table collation. However I have an old application and are not really able to estimate the outcome whether this has side effects. Therefore I tried somehow to convert the string into some other format that solved the collation problem.
What I found working is to do the string compare by converting the strings into a hexadecimal representation of it's characters. On the database this is done with HEX(column). For PHP you may use this function:
public static function strToHex($string)
{
$hex = '';
for ($i=0; $i<strlen($string); $i++){
$ord = ord($string[$i]);
$hexCode = dechex($ord);
$hex .= substr('0'.$hexCode, -2);
}
return strToUpper($hex);
}
When doing the database query, your original UTF8 string must be converted first into an iso string (e.g. using utf8_decode() in PHP) before using it in the DB. Because of the collation type the database cannot have UTF8 characters inside so the comparism should work event though this changes the original string (converting UTF8 characters that are not existend in the ISO charset result in a ? or these are removed entirely). Just make sure that when you write data into the database, that you use the same UTF8 to ISO conversion.
I had my table originally created with CHARSET=latin1. After table conversion to utf8 some columns were not converted, however that was not really obvious.
You can try to run SHOW CREATE TABLE my_table; and see which column was not converted or just fix incorrect character set on problematic column with query below (change varchar length and CHARSET and COLLATE according to your needs):
ALTER TABLE `my_table` CHANGE `my_column` `my_column` VARCHAR(10) CHARSET utf8
COLLATE utf8_general_ci NULL;
I found that using cast() was the best solution for me:
cast(Format(amount, "Standard") AS CHAR CHARACTER SET utf8) AS Amount
There is also a convert() function. More details on it here
Another resource here
Change the character set of the table to utf8
ALTER TABLE your_table_name CONVERT TO CHARACTER SET utf8
My user account did not have the permissions to alter the database and table, as suggested in this solution.
If, like me, you don't care about the character collation (you are using the '=' operator), you can apply the reverse fix. Run this before your SELECT:
SET collation_connection = 'latin1_swedish_ci';
After making your corrections listed in the top answer, change the default settings of your server.
In your "/etc/my.cnf.d/server.cnf" or where ever it's located add the defaults to the [mysqld] section so it looks like this:
[mysqld]
character-set-server=utf8
collation-server=utf8_general_ci
Source: https://dev.mysql.com/doc/refman/5.7/en/charset-applications.html