13

我在 post_content 列中有 html 内容。

我想用 B 搜索和替换 A,但只有 A 第一次出现在记录中,因为它可能出现不止一次。

下面的查询显然会用 B 替换 A 的所有实例

UPDATE wp_posts SET post_content = REPLACE (post_content, 'A', 'B');

4

9 回答 9

15

这实际上应该是您在 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));

它比我之前的答案稍微复杂一些 - 您需要找到“A”的第一个实例(使用 INSTR 函数),然后将 LEFT 与 REPLACE 结合使用来替换该实例,而不是使用 SUBSTRING 和 INSTR 找到相同的实例'A' 您正在替换并用前一个字符串连接它。

请参阅下面的测试:

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;

产生:

actual_string                                  new_string
---------------------------------------------  ---------------------------------------------
this is A string with A replace and An Answer  this is B string with A replace and An Answer
于 2012-08-25T16:07:55.633 回答
12

或者,您可以像这样使用函数LOCATE()INSERT()CHAR_LENGTH()

INSERT(originalvalue, LOCATE('A', originalvalue), CHAR_LENGTH('A'), 'B')

完整查询:

UPDATE wp_posts
SET post_content = INSERT(originalvalue, LOCATE('A', originalvalue), CHAR_LENGTH('A'), 'B');
于 2012-08-25T17:58:46.713 回答
2

参考https://dba.stackexchange.com/a/43919/200937这里是另一种解决方案:

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;

如果您有另一个字符串,例如,testing那么您需要将+1上面的内容更改为相应的字符串长度。我们可以LENGTH()用于此目的。顺便说一句,不要-1动。

示例:将“testing”替换为“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;


顺便说一句,有助于查看将影响多少行:

SELECT COUNT(*)
FROM post_content 
WHERE INSTR(post_content, 'A') > 0;
于 2020-03-08T10:13:05.490 回答
1

如果您使用的是 Oracle DB,您应该能够编写如下内容:

UPDATE wp_posts SET post_content = regexp_replace(post_content,'A','B',1,1)

有关更多信息,请参见此处:http: //docs.oracle.com/cd/B19306_01/server.102/b14200/functions130.htm

注意:您确实应该注意post_content安全问题,因为它似乎是用户输入。

于 2012-08-25T16:07:22.970 回答
1

由于 REPLACE() 的编写方式(仅替换要替换的字符串的第一个字符),Greg Reda 的解决方案不适用于长度超过 1 个字符的字符串。这是一个我认为更完整的解决方案,并且涵盖了问题的每个用例,定义为如何在“String C”中将“String A”的第一次出现替换为“String B”?

CONCAT(LEFT(buycraft, INSTR(buycraft, 'blah') - 1), '', SUBSTRING(buycraft FROM INSTR(buycraft, 'blah') + CHAR_LENGTH('blah')))

这假设您确定条目已经包含要替换的字符串!如果您尝试将字符串 'pupper' 中的 'dog' 替换为 'cat',它会给你 'per',这不是你想要的。这是一个通过首先检查要替换的字符串是否存在于完整字符串中来处理该问题的查询:

IF(INSTR(buycraft, 'blah') <> 0, CONCAT(LEFT(buycraft, INSTR(buycraft, 'blah') - 1), '', SUBSTRING(buycraft FROM INSTR(buycraft, 'blah') + CHAR_LENGTH('blah'))), buycraft)

这里的具体用例是用空字符串 '' 替换列 'buycraft' 中的第一个 'blah' 实例。我认为一个非常直观和自然的解决方案:

  1. 查找要替换的字符串第一次出现的索引。
  2. 获取左侧的所有内容,不包括索引本身(因此为'-1')。
  3. 将其与您要替换原始字符串的任何内容连接起来。
  4. 计算要替换的字符串部分的结束索引。这很容易通过再次找到第一次出现的索引并添加替换字符串的长度来完成。这将为您提供原始字符串之后的第一个字符的索引
  5. 从字符串的结束索引开始连接子字符串

将“lil_puppers_yay”中的“pupper”替换为“dog”的示例演练:

  1. 'pupper' 的索引是 5。
  2. 从 5-1 = 4 向左。所以索引 1-4,即 'lil_'
  3. 为“lil_dog”连接“狗”
  4. 计算结束索引。起始索引为 5,并且 5 + 'pupper' 的长度 = 11。请注意,索引 11 指的是 's'。
  5. 连接从结束索引开始的子字符串,即“s_yay”,以获得“lil_dogs_yay”。

全部做完!

注意: SQL 有 1-indexed 字符串(作为一个 SQL 初学者,在我发现这个问题之前我并不知道这一点)。此外,SQL LEFT 和 SUBSTRING 似乎以理想的方式使用无效索引(将其调整为字符串的开头或结尾),这对于像我这样的初学者 SQLer 来说非常方便:P

另一个注意事项:我是 SQL 的初学者,这几乎是我写过的最难的查询,所以可能会有一些效率低下。不过,它可以准确地完成工作。

于 2016-05-01T21:58:50.883 回答
1

我做了以下小功能并得到了它:

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
于 2019-03-21T19:59:28.390 回答
0

它更简单

UPDATE table_name SET column_name = CONCAT('A',SUBSTRING(column_name, INSTR(column_name, 'B') + LENGTH('A')));
于 2019-07-07T04:35:29.943 回答
0

自从提出这个问题以来已经过去了很多年,MySQL 8 引入了REGEX_REPLACE

REGEXP_REPLACE(expr, pat, repl[, pos[,occurrence[, match_type]]])

用替换字符串 repl 替换字符串 expr 中匹配由模式 pat 指定的正则表达式的匹配项,并返回结果字符串。如果 expr、pat 或 repl 为 NULL,则返回值为 NULL。

REGEXP_REPLACE()采用这些可选参数:

pos : expr 中开始搜索的位置。如果省略,则默认为
1。occurrence:要替换的匹配项。如果省略,则默认值为 0(表示“替换所有匹配项”)。
match_type:指定如何执行匹配的字符串。含义如 REGEXP_LIKE() 所述。

因此,假设您可以在您的情况下使用正则表达式:

UPDATE wp_posts SET post_content = REGEXP_REPLACE (post_content, 'A', 'B', 1, 1);

不幸的是,对于我们这些使用 MariaDB 的人来说,它的REGEXP_REPLACE风格缺少出现参数。这是Andriy M解决方案的正则表达式感知版本,按照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 ;
于 2019-07-23T15:07:35.567 回答
-1

要使 gjreda 的示例更简单,请使用以下命令:

UPDATE wp_post
    SET post_content =
            CONCAT(
                REPLACE(LEFT(post_content, 1), 'A', 'B'),
                SUBSTRING(post_content, 2)
            ) 
    WHERE post_content LIKE 'A%';
于 2014-11-12T09:29:27.533 回答