Case-insensitive REPLACE in MySQL?

后端 未结 8 2095
無奈伤痛
無奈伤痛 2020-12-05 10:00

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

相关标签:
8条回答
  • 2020-12-05 10:25

    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

    0 讨论(0)
  • 2020-12-05 10:29

    If replace(lower()) doesn't work, you'll need to create another function.

    0 讨论(0)
  • 2020-12-05 10:31

    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.

    0 讨论(0)
  • 2020-12-05 10:34

    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.

    0 讨论(0)
  • 2020-12-05 10:36

    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

    0 讨论(0)
  • 2020-12-05 10:44

    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//
    
    0 讨论(0)
提交回复
热议问题