I have html content in the post_content column.
I want to search and replace A with B but only the first time A appears in the record as it may appear more than onc
It's simpler
UPDATE table_name SET column_name = CONCAT('A',SUBSTRING(column_name, INSTR(column_name, 'B') + LENGTH('A')));
I made the following little function and got it:
CREATE DEFINER=`virtueyes_adm1`@`%` FUNCTION `replace_first`(
`p_text` TEXT,
`p_old_text` TEXT,
`p_new_text` TEXT
)
RETURNS text CHARSET latin1
LANGUAGE SQL
NOT DETERMINISTIC
CONTAINS SQL
SQL SECURITY DEFINER
COMMENT 'troca a primeira ocorrencia apenas no texto'
BEGIN
SET @str = p_text;
SET @STR2 = p_old_text;
SET @STR3 = p_new_text;
SET @retorno = '';
SELECT CONCAT(SUBSTRING(@STR, 1 , (INSTR(@STR, @STR2)-1 ))
,@str3
,SUBSTRING(@STR, (INSTR(@str, @str2)-1 )+LENGTH(@str2)+1 , LENGTH(@STR)))
INTO @retorno;
RETURN @retorno;
END
This should actually be what you want in MySQL:
UPDATE wp_post
SET post_content = CONCAT(REPLACE(LEFT(post_content, INSTR(post_content, 'A')), 'A', 'B'), SUBSTRING(post_content, INSTR(post_content, 'A') + 1));
It's slightly more complicated than my earlier answer - You need to find the first instance of the 'A' (using the INSTR function), then use LEFT in combination with REPLACE to replace just that instance, than use SUBSTRING and INSTR to find that same 'A' you're replacing and CONCAT it with the previous string.
See my test below:
SET @string = 'this is A string with A replace and An Answer';
SELECT @string as actual_string
, CONCAT(REPLACE(LEFT(@string, INSTR(@string, 'A')), 'A', 'B'), SUBSTRING(@string, INSTR(@string, 'A') + 1)) as new_string;
Produces:
actual_string new_string
--------------------------------------------- ---------------------------------------------
this is A string with A replace and An Answer this is B string with A replace and An Answer
With reference to https://dba.stackexchange.com/a/43919/200937 here is another solution:
UPDATE wp_posts
SET post_content = CONCAT( LEFT(post_content , INSTR(post_content , 'A') -1),
'B',
SUBSTRING(post_content, INSTR(post_content , 'A') +1))
WHERE INSTR(post_content , 'A') > 0;
If you have another string, e.g. testing
then you need to change the +1
above to the according string length. We can use LENGTH()
for this purpose. By the way, leave the -1
untouched.
Example: Replace "testing" with "whatever":
UPDATE wp_posts
SET post_content = CONCAT( LEFT(post_content , INSTR(post_content , 'testing') -1),
'whatever',
SUBSTRING(post_content, INSTR(post_content , 'testing') + LENGTH("testing"))
WHERE INSTR(post_content , 'testing') > 0;
By the way, helpful to see how many rows will be effected:
SELECT COUNT(*)
FROM post_content
WHERE INSTR(post_content, 'A') > 0;
Years have passed since this question was asked, and MySQL 8 has introduced REGEX_REPLACE:
REGEXP_REPLACE(expr, pat, repl[, pos[, occurrence[, match_type]]])
Replaces occurrences in the string expr that match the regular expression specified by the pattern pat with the replacement string repl, and returns the resulting string. If expr, pat, or repl is NULL, the return value is NULL.
REGEXP_REPLACE() takes these optional arguments:
pos: The position in expr at which to start the search. If omitted, the default is 1.
occurrence: Which occurrence of a match to replace. If omitted, the default is 0 (which means “replace all occurrences”).
match_type: A string that specifies how to perform matching. The meaning is as described for REGEXP_LIKE().
So, assuming you can use regular expressions in your case:
UPDATE wp_posts SET post_content = REGEXP_REPLACE (post_content, 'A', 'B', 1, 1);
Unfortunately for those of us on MariaDB, its REGEXP_REPLACE flavor is missing the occurrence parameter. Here's a regex-aware version of Andriy M's solution, conveniently stored as a reusable function as suggested by Luciano Seibel:
DELIMITER //
DROP FUNCTION IF EXISTS replace_first //
CREATE FUNCTION `replace_first`(
`i` TEXT,
`s` TEXT,
`r` TEXT
)
RETURNS text CHARSET utf8mb4
BEGIN
SELECT REGEXP_INSTR(i, s) INTO @pos;
IF @pos = 0 THEN RETURN i; END IF;
RETURN INSERT(i, @pos, CHAR_LENGTH(REGEXP_SUBSTR(i, s)), r);
END;
//
DELIMITER ;
Greg Reda's solution did not work for me on strings longer than 1 character because of how the REPLACE() was written (only replacing the first character of the string to be replaced). Here is a solution that I believe is more complete and covers every use case of the problem when defined as How do I replace the first occurrence of "String A" with "String B" in "String C"?
CONCAT(LEFT(buycraft, INSTR(buycraft, 'blah') - 1), '', SUBSTRING(buycraft FROM INSTR(buycraft, 'blah') + CHAR_LENGTH('blah')))
This assumes that you are sure that the entry ALREADY CONTAINS THE STRING TO BE REPLACED! If you try replacing 'dog' with 'cat' in the string 'pupper', it will give you 'per', which is not what you want. Here is a query that handles that by first checking to see if the string to be replaced exists in the full string:
IF(INSTR(buycraft, 'blah') <> 0, CONCAT(LEFT(buycraft, INSTR(buycraft, 'blah') - 1), '', SUBSTRING(buycraft FROM INSTR(buycraft, 'blah') + CHAR_LENGTH('blah'))), buycraft)
The specific use case here is replacing the first instance of 'blah' inside column 'buycraft' with an empty string ''. I think a pretty intuitive and natural solution:
An example walkthrough of replacing "pupper" in "lil_puppers_yay" with 'dog':
All done!
Note: SQL has 1-indexed strings (as an SQL beginner, I didn't know this before I figured this problem out). Also, SQL LEFT and SUBSTRING seem to work with invalid indexes the ideal way (adjusting it to either the beginning or end of the string), which is super convenient for a beginner SQLer like me :P
Another Note: I'm a total beginner at SQL and this is pretty much the hardest query I've ever written, so there may be some inefficiencies. It gets the job done accurately though.