MySQL UPPER() and LOWER() not working with utf-8 characters - mysql

I have a search function, I want it to be case insensitive, including characters like éüò etc.
So, i transform the input to uppercase before querying the database. But MySQL doesn't convert the accented characters right.
SELECT * FROM items WHERE UPPER(description) = $input
I have MySQL 5.1.32, i have tried different collations but none seem to work right. Same with LOWER().
CREATE TABLE `items` (
`id` int(11) NOT NULL AUTO_INCREMENT,
`name` varchar(255) DEFAULT NULL,
`description` text CHARACTER SET utf8 COLLATE utf8_bin,
PRIMARY KEY (`id`)
) ENGINE=MyISAM AUTO_INCREMENT=187 DEFAULT CHARSET=utf8"
The description field contains 'hellö'. Mysql converts it to 'HELLö'. I want 'HELLÖ'.

This works for me:
CREATE TABLE items (id INT NOT NULL, name VARCHAR(100) COLLATE UTF8_GENERAL_CI) ENGINE=InnoDB;
INSERT
INTO items
VALUES (1, 'Eyjafjallajökull');
SELECT *
FROM items
WHERE name = 'EYJAFJALLAJOKULL';
--
1 Eyjafjallajökull
SELECT UPPER('Eyjafjallajökull')
FROM items;
--
EYJAFJALLAJÖKULL

Related

MySQL select not work correctly on fields contain accents

Hi guys i have a problem with my DB, in detail i have this table:
CREATE TABLE `energy_vector` (
`id` char(36) NOT NULL,
`creation_date` datetime DEFAULT NULL,
`modification_date` datetime DEFAULT NULL,
`denomination` varchar(255) DEFAULT NULL,
`aliases` longtext,
PRIMARY KEY (`id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8 DEFAULT COLLATE utf8_general_ci;
This table contain some rows and in particular the problem is on these two rows:
INSERT INTO `energy_vector` (`id`, `creation_date`, `modification_date`, `denomination`, `aliases`) VALUES
('e4814054-5345-7ece-90aa-59e74b0008bb', '2017-10-18 14:38:44', '2017-11-15 15:17:10', 'Elettricità approvvigionata dalla rete elettrica', NULL),
('e59a4f52-8bba-734e-4a5e-59e74b464564', '2017-10-18 14:38:44', '2017-11-15 15:18:09', 'Elettricità prodotta da fonti rinnovabili', NULL);
Note that both rows contain a string with accent in the column denomination.
Now i execute these two queries:
First:
select * from energy_vector where denomination = 'Elettricità prodotta da fonti rinnovabili';
Second:
select * from energy_vector where denomination = 'Elettricità approvvigionata dalla rete elettrica';
First query return the row that i search and match correctly the string, but the Second query return me nothing. Why?
I checked a billions of time that the string is correct but i think it's a problem of the accent bound to charset or collation. Can anyone have a solution and explain me why? Thank you in advance.
MySQL version: 10.0.31-MariaDB

MySQL SHA1 hash does not match

I have a weird problem with a MySQL users table. I have quickly created a simplified version as a testcase.
I have the following table
CREATE TABLE IF NOT EXISTS `users` (
`id` int(11) NOT NULL AUTO_INCREMENT,
`identity` varchar(255) NOT NULL,
`credential` varchar(255) NOT NULL,
`credentialSalt` varchar(255) NOT NULL,
PRIMARY KEY (`id`)
) ENGINE=InnoDB DEFAULT CHARSET=ucs2 AUTO_INCREMENT=2 ;
INSERT INTO `users` (`id`, `identity`, `credential`, `credentialSalt`) VALUES
(1, 'test', '7288edd0fc3ffcbe93a0cf06e3568e28521687bc', '123');
And I run the following query
SELECT id,
IF (credential = SHA1(CONCAT('test', credentialSalt)), 1, 0) AS dynamicSaltMatches,
credentialSalt AS dynamicSalt,
SHA1(CONCAT('test', credentialSalt)) AS dynamicSaltHash,
IF (credential = SHA1(CONCAT('test', 123)), 1, 0) AS staticSaltMatches,
123 AS staticSalt,
SHA1(CONCAT('test', 123)) AS staticSaltHash
FROM users
WHERE identity = 'test'
Which gives me the following result
The dynamic salt does NOT match while the static salt DOES match.
This is blowing my mind. Can someone help me point out the cause of this?
My MySQL version is 5.5.29
It's because of the default character set of your table. You appear to be running this on a UTF8 database and something in SHA1() is having problems with the differing character sets.
If you change your table declaration to the following it will match again:
CREATE TABLE IF NOT EXISTS `users` (
`id` int(11) NOT NULL AUTO_INCREMENT,
`identity` varchar(255) NOT NULL,
`credential` varchar(255) NOT NULL,
`credentialSalt` varchar(255) NOT NULL,
PRIMARY KEY (`id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8 AUTO_INCREMENT=2 ;
SQL Fiddle
As robertklep commented explicitly casting your string to a character will also work, basically ensure you're using the same characterset when doing comparisons using SHA1()
As the encryption functions documentation says:
Many encryption and compression functions return strings for which the result might contain arbitrary byte values. If you want to store these results, use a column with a VARBINARY or BLOB binary string data type. This will avoid potential problems with trailing space removal or character set conversion that would change data values, such as may occur if you use a nonbinary string data type (CHAR, VARCHAR, TEXT).
This was changed in version 5.5.3:
As of MySQL 5.5.3, the return value is a nonbinary string in the connection character set. Before 5.5.3, the return value is a binary string; see the notes at the beginning of this section about using the value as a nonbinary string.

mysql match against not return case insensitive results

I have two tables:
CREATE TABLE IF NOT EXISTS `test1` (
`id` int(10) unsigned NOT NULL AUTO_INCREMENT,
`bucket_id` int(10) unsigned NOT NULL COMMENT 'folder this component belongs to',
`test1_name` varchar(81) NOT NULL COMMENT 'Name of this component',
`test1_desc` varchar(1024) NOT NULL COMMENT 'Component Description',
PRIMARY KEY (`id`),
FULLTEXT KEY `test1_search` (`test1_name`,`test1_desc`)
) ENGINE=MyISAM DEFAULT CHARSET=utf8 AUTO_INCREMENT=3 ;
CREATE TABLE IF NOT EXISTS `bucket` (
`id` int(10) unsigned NOT NULL AUTO_INCREMENT,
`bkt_name` varchar(81) NOT NULL COMMENT 'The name of this bucket',
`bkt_desc` varchar(1024) NOT NULL COMMENT 'A description of this bucket',
`bkt_keywords` varchar(512) DEFAULT NULL COMMENT 'keywords for searches',
PRIMARY KEY (`id`),
FULLTEXT KEY `fldr_search` (`bkt_desc`,`bkt_keywords`,`bkt_name`)
) ENGINE=MyISAM DEFAULT CHARSET=utf8 AUTO_INCREMENT=8 ;
Bucket is just a holder while test1 contains all the things that would go into a bucket. For example:
INSERT INTO `bucket` (`id`, `bkt_name`, `bkt_desc`, `bkt_keywords`) VALUES
(1, 'Simpsons', 'The Simpsons Cartoon Family was first successful adult cartoon series', 'Homer, Marge, Lisa and Bart'),
(2, 'Griffins', 'The family from the popular family guy series', 'Peter, Lois, Meg, Chris, Stewie, Brian');
INSERT INTO `test1` (`id`, `bucket_id`, `bkt_name`, `bkt_desc`) VALUES
(1, 1, 'Homer Simpson', 'Homer the figurative head of the Simpsons Family and is the husband of Marge'),
(2, 2, 'Peter Griffin', 'Peter the figurative head of the Griffin family on the hit TV seriers The family Guy');
Now, using the following query I want to look for all buckets whose name, description or keywords contain the search term "family" or whose components contain the words "family")
So far, what I have is this query and it's not returning mixed case results as in "Family" is not found while "family" is.
SELECT *
FROM bucket
RIGHT JOIN test1 ON test1.bucket_id = bucket.id
WHERE
bucket.isvisible > 0 AND
MATCH(bucket.bkt_keywords, bucket.bkt_desc, bucket.bkt_name)
AGAINST('family' IN BOOLEAN MODE) OR
MATCH(test1.test1_name, test1.test1_desc)
AGAINST('family' IN BOOLEAN MODE)
I should also add that all text fields have the collation of utf8_general_ci as does the entire table which is MyISAM.
I think your tables do not use utf8_general_ci as collation, but utf8_bin. I was able to reproduce the behaviour you describe after modifying the tables as follows:
ALTER TABLE test1 CONVERT TO CHARACTER SET utf8 COLLATE utf8_bin;
ALTER TABLE bucket CONVERT TO CHARACTER SET utf8 COLLATE utf8_bin;
You should perhaps set your tables' collation explicitely to:
ALTER TABLE test1 CONVERT TO CHARACTER SET utf8 COLLATE utf8_general_ci;
ALTER TABLE bucket CONVERT TO CHARACTER SET utf8 COLLATE utf8_general_ci;
If the above changes anything, I would guess your server or session is actually set to use another collation by default (since the collation is not specified in your tables definition). This could be checked with:
SHOW GLOBAL VARIABLES LIKE 'collation_server';
SHOW SESSION VARIABLES LIKE 'collation_server';
The answer is apparently adding some parens around the two match against clauses.
SELECT *
FROM bucket
RIGHT JOIN test1 ON test1.bucket_id = bucket.id
WHERE bucket.isvisible > 0 AND
( MATCH(bucket.bkt_keywords, bucket.bkt_desc, bucket.bkt_name)
AGAINST('family' IN BOOLEAN MODE) OR
MATCH(test1.test1_name, test1.test1_desc)
AGAINST('family' IN BOOLEAN MODE) )

What does 'Execute failed: (1062) Duplicate entry 'X' for key 'Y'' mean?

I am trying to add X to some table in my DB, but I am getting this error. Even if X doesn't exist in the table, it say it's there. Although X is added to the DB, I want to get rid of this error. I don't know if it's relevant at all, but I'm using Mysqli's prepared statements and this error is printed using $statement->errno." ".$statement->error. Could someone explain this to me? Thanks.
UPDATE: this is the code: X = USER_USERNAME
$stmt = $mysqli->prepare("INSERT INTO USERS (USER_USERNAME, USER_EMAIL, USER_BIRTHDAY, USER_PASSWORD, USER_SALT, USER_IP, USER_ACTIVATION_CODE) VALUES (?,?,?,?,?,INET_ATON(?),?)");
$stmt->bind_param('sssssss',$username,$email,$date,$hashed_password,$salt,$IP,$activation_code);
$stmt->execute();
if (!$stmt->execute()) {
echo "Execute failed: (" . $stmt->errno . ") " . $stmt->error;
}
else {
echo "ok";
}
SHOW CREATE TABLE USERS:
CREATE TABLE `USERS` (
`USER_ID` int(11) NOT NULL AUTO_INCREMENT,
`USER_FIRSTNAME` varchar(100) CHARACTER SET utf8 DEFAULT NULL,
`USER_LASTNAME` varchar(100) CHARACTER SET utf8 DEFAULT NULL,
`USER_USERNAME` varchar(30) CHARACTER SET utf8 DEFAULT NULL,
`USER_PASSWORD` varchar(128) CHARACTER SET utf8 DEFAULT NULL,
`LEVEL_ID` int(11) NOT NULL,
`USER_BIRTHDAY` date DEFAULT NULL,
`USER_EMAIL` varchar(100) CHARACTER SET utf8 DEFAULT NULL,
`USER_GENDER` enum('M','W','U') CHARACTER SET utf8 DEFAULT NULL,
`USER_COUNTRY` varchar(30) CHARACTER SET utf8 DEFAULT NULL,
`USER_LOCATION` varchar(30) CHARACTER SET utf8 DEFAULT NULL,
`USER_ADDRESS` varchar(50) CHARACTER SET utf8 DEFAULT NULL,
`USER_HOUSENUMBER` varchar(8) CHARACTER SET utf8 DEFAULT NULL,
`USER_AVATAR` varchar(50) CHARACTER SET utf8 DEFAULT NULL,
`USER_REGISTRATION_DATE` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP,
`USER_ACTIVATION_DATE` timestamp NOT NULL DEFAULT '0000-00-00 00:00:00',
`USER_STATUS` enum('REGISTERED','ACTIVE','BANNED','NONACTIVE') CHARACTER SET utf8 DEFAULT NULL,
`USER_BANNED_DATE` timestamp NOT NULL DEFAULT '0000-00-00 00:00:00',
`USER_LATEST_LOGIN` timestamp NOT NULL DEFAULT '0000-00-00 00:00:00',
`USER_EXP` bigint(20) DEFAULT NULL,
`USER_DESCRIPTION` text CHARACTER SET utf8,
`USER_ACTIVATION_CODE` varchar(32) CHARACTER SET utf8 NOT NULL DEFAULT '0',
`USER_SALT` varchar(15) CHARACTER SET utf8 NOT NULL,
`USER_IP` int(10) NOT NULL,
`USER_REMEMBER_KEY` varchar(32) CHARACTER SET utf8 NOT NULL,
PRIMARY KEY (`USER_ID`),
UNIQUE KEY `USER_USERNAME` (`USER_USERNAME`),
UNIQUE KEY `USER_EMAIL` (`USER_EMAIL`),
KEY `LEVEL_ID` (`LEVEL_ID`)
) ENGINE=MyISAM AUTO_INCREMENT=30 DEFAULT CHARSET=latin1
that's because you are trying to insert or update a value violating a constraint (like PK or UK), for example
if your Table have ID an it's a PK or a Unique Key, you can only have ONE UNIQUE VALUE... it's not possible no repeated....
with a Unique Key you can have Null... but never repeat values in the same column, because you will be breaking the constraint... for more information take a look to http://dev.mysql.com/doc/refman/5.0/es/constraints.html
You already defined a Primary or Unique Key, but again you tried to insert the same value. That time since already there exists a same value, it is not possible to have a redundant value for the primary key or unique key.
It is something like this. Consider you have a table with id and name, with id as primary key. You insert first row as:
INSERT INTO `users` (`id`, `name`) VALUES (1, 'Praveen');
INSERT INTO `users` (`id`, `name`) VALUES (1, 'Kumar');
The second query violates the id uniqueness.
Solution: Try to truncate the table and then run the query again, if it is possible.
Some steps to try
Check for other fields with unique constraints being violated too.
See what query is getting generated.
Put the same query in phpMyAdmin and check.
If you are getting that error then X does exist in the table. Apparently you have not noticed it, but it's there. (Check for things like trimmed spaces, and case sensitivity.)
If you don't get the error in phpMyAdmin then the query you think you are sending is not actually the query you are sending. Most likely you are sending blank for the field, and after you do it once, all further query are using the identical blank value.
Easiest way to check is delete everything from the table (copy it elsewhere first if you want). Then run the query and see what actually got inserted vs. what you expected to get inserted.
You are probably trying to insert a record with the ID (or some other field) 1 set, while such a record already exists in the table. The field that is the primary key must have a unique value for each record.
You could try a simple error check to avoid this error:
$rows = mysql_query("SELECT X from tablenme WHERE X = Y;");
if(mysql_num_rows($rows) > 0){
echo 'Error Messege';
}else{
insert...
}
where X is the primary key or foregin key column and Y is the value to be inserted in that column.
EDIT: Some of the problems that might have caused the problem may be that you have not specified certain columns that can't be null in you insert statement.
Like LEVEL_ID and USER_REMEMBER_KEY. They are set to NOT NULL but the values are not being inserted using the insert statement.
I also don't understand why you are inserting 'sssssss' when the first column is USER_USERNAME and its corresponding value is $username. Do check that too.
SQL Fiddle

Saving and retrieving URL from MYSQL

I am trying to save an URL in mysql db and get it back in my application. It gets saved properly.
http://i.>/00/s/NTAwWDUwMA==/$(KGrHqZHJC4E8fW,EPnUBPN1zoBtIQ~~60_1.JPG?set_id=8800005007
but while retrieving, all the '.' operators in the URL gets replaced by
http://i�domain�com/00/s/NTAwWDUwMA==/$�KGrHqZHJC4E8fW�EPnUBPN1zoBtIQ~~60_1�JPG?set_id=8800005007
Is there a way to remove those special characters. Attaching the create script for the table..
Im getting the url from the result set.
rs.getString(image)
delimiter $$
CREATE TABLE `livedeals` (
`ItemID` bigint(20) NOT NULL,
`category` varchar(200) CHARACTER SET latin1 NOT NULL,
`deal_like` int(4) NOT NULL,
`deal_dislike` int(4) NOT NULL,
`image` varchar(200) CHARACTER SET armscii8 COLLATE armscii8_bin NOT NULL
) ENGINE=InnoDB DEFAULT CHARSET=utf8$$
any help would be helpful.
thanks.
If for some reason you can't change the character set of the table, then you could get that field the following way:
SELECT CAST(image AS CHAR CHARACTER SET utf8) AS image2 FROM livedeals