MySQL runs pretty much all string comparisons under the default collation... except the REPLACE
command. I have a case-insensitive collation and need to run a
My 2 cents.
Since many people have upgraded from MySQL to MariaDB those people will have available a new function called REGEXP_REPLACE
. Use it as you would a normal replace, but the pattern is a regular expression.
This is a working example:
UPDATE `myTable`
SET `myField` = REGEXP_REPLACE(`myField`, '(?i)my insensitive string', 'new string')
WHERE `myField` REGEXP '(?i)my insensitive string'
The option (?i)
makes all the subsequent matches case insensitive (if put at the beginning of the pattern like I have then it all is insensitive).
See here for more information: https://mariadb.com/kb/en/mariadb/pcre/
Edit: as of MySQL 8.0 you can now use the regexp_replace
function too, see documentation: https://dev.mysql.com/doc/refman/8.0/en/regexp.html
If replace(lower())
doesn't work, you'll need to create another function.
I went with http://pento.net/2009/02/15/case-insensitive-replace-for-mysql/ (in fvox's answer) which performs the case insensitive search with case sensitive replacement and without changing the case of what should be unaffected characters elsewhere in the searched string.
N.B. the comment further down that same page stating that CHAR(255) should be changed to VARCHAR(255) - this seemed to be required for me as well.
In the previous answers, and the pento.net link, the arguments to LOCATE()
are lower-cased.
This is a waste of resources, as LOCATE is case-insensitive by default:
mysql> select locate('el', 'HELLo');
+-----------------------+
| locate('el', 'HELLo') |
+-----------------------+
| 2 |
+-----------------------+
You can replace
WHILE Locate( LCASE(REPLACE_THIS), LCASE(REPLACE_WHERE), last_occurency ) > 0 DO
with
WHILE Locate(REPLACE_THIS, REPLACE_WHERE, last_occurency ) > 0 DO
etc.
Alternative function for one spoken by fvox.
DELIMITER |
CREATE FUNCTION case_insensitive_replace ( REPLACE_WHERE text, REPLACE_THIS text, REPLACE_WITH text )
RETURNS text
DETERMINISTIC
BEGIN
DECLARE last_occurency int DEFAULT '1';
IF LCASE(REPLACE_THIS) = LCASE(REPLACE_WITH) OR LENGTH(REPLACE_THIS) < 1 THEN
RETURN REPLACE_WHERE;
END IF;
WHILE Locate( LCASE(REPLACE_THIS), LCASE(REPLACE_WHERE), last_occurency ) > 0 DO
BEGIN
SET last_occurency = Locate(LCASE(REPLACE_THIS), LCASE(REPLACE_WHERE));
SET REPLACE_WHERE = Insert( REPLACE_WHERE, last_occurency, LENGTH(REPLACE_THIS), REPLACE_WITH);
SET last_occurency = last_occurency + LENGTH(REPLACE_WITH);
END;
END WHILE;
RETURN REPLACE_WHERE;
END;
|
DELIMITER ;
Small test:
SET @str = BINARY 'New York';
SELECT case_insensitive_replace(@str, 'y', 'K');
Answers: New Kork
I like to use a search and replace function I created when I need to replace without worrying about the case of the original or search strings. This routine bails out quickly if you pass in an empty/null search string or a null replace string without altering the incoming string. I also added a safe count down just in case somehow the search keep looping. This way we don't get stuck in a loop forever. Alter the starting number if you think it is too low.
delimiter //
DROP FUNCTION IF EXISTS `replace_nocase`//
CREATE FUNCTION `replace_nocase`(raw text, find_str varchar(1000), replace_str varchar(1000)) RETURNS text
CHARACTER SET utf8
DETERMINISTIC
BEGIN
declare ret text;
declare len int;
declare hit int;
declare safe int;
if find_str is null or find_str='' or replace_str is null then
return raw;
end if;
set safe=10000;
set ret=raw;
set len=length(find_str);
set hit=LOCATE(find_str,ret);
while hit>0 and safe>0 do
set ret=concat(substring(ret,1,hit-1),replace_str,substring(ret,hit+len));
set hit=LOCATE(find_str,ret,hit+1);
set safe=safe-1;
end while;
return ret;
END//