【问题标题】:Find and replace string in MySQL using data from another table使用来自另一个表的数据在 MySQL 中查找和替换字符串
【发布时间】:2010-03-24 17:13:58
【问题描述】:

我有两个 MySQL 表,我想使用另一个表中的数据查找和替换其中的文本字符串。

texts:

+---------------------+
|      messages       |
+---------------------+
| 'thx guys'          |
| 'i think u r great' |
| 'thx again'         |
| ' u rock'           |
+---------------------+

dictionary

+--------------+---------------+
| bad_spelling | good_spelling |
+--------------+---------------+
|    'thx'     |    'thanks'   |
|    ' u '     |    ' you '    |
|    ' r '     |    ' are '    |
+--------------+---------------+

我希望 SQL 遍历并查看消息中的每一行,并将 bad_spelling 的每个实例替换为 good_spelling,并对所有 bad_spelling 和 good_spelling 对执行此操作。

我得到的最接近的是:

update texts, dictionary
set texts.message = replace(texts.message,
                            dictionary.bad_spelling,
                            dictionary.good_spelling)

但这只会将“thx”更改为“thanks”(在两行中),并且不会继续将“u”替换为“you”或“r”替换为“are”。

任何想法如何使它在替换语句中使用字典中的所有行?


PS 忘了提到这是一个小例子,实际上我会有很多查找/替换对,随着时间的推移可能会添加。

【问题讨论】:

    标签: sql mysql


    【解决方案1】:

    我从未使用过 MySql,所以这只是基于我的其他数据库工作的一个理论。在阅读其他答案时,尝试使用 REPLACE(),我想我可以发布这个并让具有 MySql 语法经验的人提出一些想法来制定一套基本解决方案。

    这里有一些 SQL Server 代码可以为您完成大部分工作:

    DECLARE @Source table (Texts varchar(50))
    INSERT @Source VALUES ('thx guys')
    INSERT @Source VALUES ('i think u r great')
    INSERT @Source VALUES ('thx again')
    INSERT @Source VALUES ('u rock')
    
    DECLARE @Dictionary table (bad_spelling varchar(50), good_spelling varchar(50))
    INSERT @Dictionary VALUES ('thx', 'thanks')
    INSERT @Dictionary VALUES ('u', 'you')
    INSERT @Dictionary VALUES ('r', 'are')
    
    SELECT
        t.Texts,COALESCE(d.good_spelling,c.ListValue) AS WordToUse
        FROM @Source                                     t
            CROSS APPLY dbo.FN_ListToTable(' ',t.Texts)  c
            LEFT OUTER JOIN @Dictionary                  d ON c.ListValue=d.bad_spelling
    

    输出:

    Texts              WordToUse
    ------------------ ---------
    thx guys           thanks
    thx guys           guys
    i think u r great  i
    i think u r great  think
    i think u r great  you
    i think u r great  are
    i think u r great  great
    thx again          thanks
    thx again          again
    u rock             you
    u rock             rock
    
    (11 row(s) affected)
    

    在上面的查询中使用“真正的”PK 比使用实际的“文本”更好,但是 OP 没有在该表中列出很多列,所以我使用“文本”。

    使用 SQL Server,您需要使用一些时髦的 XML 语法将行重新连接在一起(所以我不会显示该代码,因为这无关紧要),但是使用 MySql 的 GROUP_CONCAT() 您应该能够将单词行重新连接成短语行。

    (SQL Server)拆分函数的代码及其工作原理可以在这里找到:SQL Server: Split operation

    【讨论】:

      【解决方案2】:

      它不会一直进行,因为即使替换已运行 x 次(其中 x 是字典中的行数),也只保留了一次更新(最后一次)。

      事务不会记下中间结果,因此不能将它们视为下一批替换的输入值。

      由于 (AFAIK) MySQL 不支持递归查询,您将不得不求助于过程方法。

      【讨论】:

        【解决方案3】:

        无论如何,您都需要多次执行查询。由于这是clean-up类型的操作,你通常偶尔会这样做,我建议你执行以下查询,直到有更新。我不知道如何使用MySql,但在SQL Server 中将检查更新的行数(这是UPDATE 查询执行的结果),然后再次运行UPDATE,直到没有更新任何行。

        update  texts, 
                dictionary
        set     texts.message = replace(texts.message, dictionary.bad_spelling, dictionary.good_spelling)
        where   texts.message <> replace(texts.message, dictionary.bad_spelling, dictionary.good_spelling)
        

        【讨论】:

        • 谢谢 Van,我认为这是赢家 :) 我将使用 PHP 在同一个数据集上运行一大堆 SQL 查询,所以我想我可以使用 mysql_affected_rows 并告诉它重复查询直到 0 行受到影响。
        【解决方案4】:

        你必须在文本上多次调用 Replace:

        Update ...
        Set texts.message = Replace(
                                Replace(
                                    Replace( texts.message, 'thx ', 'thanks ' )
                                    , ' u ', ' you ')
                                , ' r ', ' are ')
        

        编辑 鉴于您说您有很多替换,您需要在具有多个 UPDATE 语句调用的游标中执行此操作。类似的东西(我根本没有测试过,所以要小心):

        Create Temporary Table ReplaceValues 
            (
            BeforeText varchar(100) not null
            , AfterText varchar(100) not null
            )
        
        Insert ReplaceValues(BeforeText, AfterText) Values('thx ', 'thanks ')
        Insert ReplaceValues(BeforeText, AfterText) Values(' u ', ' you ')
        Insert ReplaceValues(BeforeText, AfterText) Values(' r ', ' are ')
        
        DECLARE done int DEFAULT(0)
        DECLARE BeforeValue varchar(100);
        DECLARE AfterValue varchar(100);
        DECLARE CONTINUE HANDLER FOR NOT FOUND SET done = 1;
        
        DECLARE ReplaceList CURSOR FOR Select BeforeText, AfterText From ReplaceValues;
        
        OPEN ReplaceList;   
        
        REPEAT
            If NOT done THEN
                FETCH ReplaceList INTO BeforeValue, AfterValue;
        
                Update texts
                Set texts.message = REPLACE(texts.message, BeforeValue, AfterValue);
            END IF  
        UNTIL done END REPEAT;
        CLOSE ReplaceList;
        

        您可以将所有这些包装到一个过程中,以便以后再次调用它。

        【讨论】:

        • 谢谢托马斯,在我向你展示的情况下,这是正确的做法,但我忘了提到,对于真正的事情,我将有很多对来替换(和它们可能会随着时间而改变),这就是为什么我想将它们列在一个单独的表格中。
        • 不幸的是,答案是相同的(对于单个语句):多次替换调用。唯一的另一种方法是通过游标在循环中执行此操作,在该游标中使用“之前”和“之后”文本填充临时表,并在每次循环中调用更新语句。
        猜你喜欢
        • 2014-02-19
        • 2011-12-23
        • 1970-01-01
        • 2020-06-03
        • 1970-01-01
        • 1970-01-01
        • 2019-04-18
        • 1970-01-01
        • 2012-09-11
        相关资源
        最近更新 更多