【问题标题】:MySQL: using REPLACE with a JOIN?MySQL:将 REPLACE 与 JOIN 一起使用?
【发布时间】:2012-01-27 12:22:12
【问题描述】:

我需要在一个文本字段中替换 多个 个不同的单词。

搜索和替换值在另一个表中。

例如文本表是:

The Quick Brown Fox
The Dirty Red Bandana

使用这样的替换表:

SearchValue         ReplaceValue
  Quick               Slow
  Fox                 Wolf
  Dirty               Clean
  Bandana             Hat

被替换的记录会变成:

The Slow Brown Wolf
The Clean Red Hat

是否可以通过 JOIN 来做到这一点?

类似:

UPDATE texts_table AS tt
CROSS JOIN values_table AS vt
SET tt.Text= REPLACE(tt.Text, vt.SearchValue, vt.ReplaceValue)

我尝试了一些不同的方法,但无法替换文本字段中的 all 字符串。

【问题讨论】:

    标签: mysql join replace


    【解决方案1】:

    你需要指定一个Join条件,比如这样:

    UPDATE texts_table AS tt
    INNER JOIN values_table AS vt 
       on tt.valueId = vt.valudId /*or whatever the join condition*/ 
    SET tt.Text= REPLACE(tt.Text, vt.SearchValue, vt.ReplaceValue)
    

    UPDATE 子句的语法中指定:

    UPDATE [LOW_PRIORITY] [IGNORE] table_reference
    

    table_references 子句列出了连接中涉及的表。其语法描述为JOIN Syntax

    【讨论】:

    • 我省略了 ON 条件,因为我不知道如何指定它,现在仍然不知道。如果我使用 CROSS JOIN(没有条件),在 texts_table 中有 2 条记录,不知何故只有 LAST 记录中的 LAST 单词被替换。
    • @Dylan 您需要根据表的结构和要选择的数据来指定连接子句以更新它,CROSS JOIN 会将第一个表中的每一行与每个第二个表中的行,所以你得到了两个表中行的笛卡尔积,所以我认为这对你不起作用。所以尝试使用左连接或其他连接。
    【解决方案2】:

    JOIN 是错误的方法。 JOIN 的结果行是通过组合每个连接表中的单行来创建的。这不适合您想做的事情。对于SELECT,将JOINGROUP BY 结合起来会更有意义,尽管UPDATE 中没有GROUP BY 子句,所以这不是一个选项。

    SQL 不是为这种文本操作而设计的。它应该由编程语言来执行,而不是数据语言。

    对于SELECT,您可以通过编写user defined aggregate 函数来强制SQL 完成这项工作,例如:

    /**
     * make_string: Strings hold both character sequence and a length. Strings can 
     * hold null characters and are null terminated for safety, in case they hold 
     * C-strings, but the null character shouldn't be used as a terminator by any 
     * string function.
     *
     * @param data: characters to copy to string
     * @param len: number of characters to copy from data
     * @param size: number of characters to allocate; lets you allocate extra space. 
     *     If size < len, size is set to len, so you can pass 0 to not allocate 
     *     extra space.
     */
    string_t* make_string(const char *data, int len, int size);
    string_t* delete_string(string_t* str);
    char* string_data(string_t* str);
    int string_length(string_t* str);
    /**
     * Copy data to str's buffer, replacing whatever was stored there previously.
     *
     * @returns 0 on success, non-0 on failure.
     */
    int string_set(string_t* str, const char* data, int len);
    /**
     * Replace first occurrence of 'search' in 'str' with 'replace', starting the 
     * search at character 'start'.
     *
     * If there isn't enough space in str's buffer, resize the buffer. If there is 
     * enough space, must always succeed.
     *
     * @returns position of character after replaced section, or -1 if search isn't found.
     */
    int string_replace(string_t* str, string_t* search, string_t* replace, int start);
    ...
    
    my_bool group_replace_init(UDF_INIT *initid, UDF_ARGS *args, char *message) {
        if (args->arg_count != 3) {
            strcpy(message,"wrong argument count: group_replace(str, search, replacement) requires three string arguments");
            return 1;
        }
        initid->maybe_null = 1;
        initid->max_length = args->lengths[0];
        if (! (initid->ptr = make_string("", 0, args->lengths[0])) ) {
            snprintf(message, MYSQL_ERRMSG_SIZE, "error allocating string for group_replace: %s", strerror(errno));
            return 1;
        }
        return 0;
    }
    
    void group_replace_deinit(UDF_INIT *initid) {
        delete_string(initid->ptr);
    }
    
    void group_replace_clear(UDF_INIT *initid, char *is_null, char *error) {
        string_set(initid->ptr, "", 0);
        // result will be null, until 
        *is_null = 1;
        *error = 0;
    }
    
    void group_replace_add(UDF_INIT *initid, UDF_ARGS *args, char *is_null, char *error) {
        if (*error) {
            return;
        }
        if (*is_null && args->args[0]) {
            if (string_set(initid->ptr, args->args[0], args->lengths[0])) {
                *error = 1;
                return;
            }
            *is_null = 0;
        }
        string_t *search, *replacement;
        if (! (search = make_string(args->args[1], args->lengths[1])) ) {
            *error = 1;
            return;
        }
        if (! (replacement = make_string(args->args[2], args->lengths[2])) ) {
            delete_string(search);
            *error = 1;
            return;
        }
        int pos=0;
        do {
            pos = string_replace(initid->ptr, search, replacement, pos);
        } while (0 <= pos);
    }
    char* group_replace(UDF_INIT *initid, UDF_ARGS *args,
                        char *result, unsigned long *length,
                        char *is_null, char *error)
    {
        if (*is_null) {
            *length = 0;
            return null;
        }
        *length = string_length(initd->ptr);
        return string_data(initid->ptr);
    }
    

    以上:

    • 未经测试。
    • 将(大概)区分大小写(取决于您如何实现string_replace),这与MySQL 的其他字符串函数的行为不同。对于不区分大小写,实现并使用string_ireplace 函数。

    作为练习留下的字符串函数的实现。

    相应的SELECT 语句将是:

    SELECT tt.id, GROUP_REPLACE(tt.Text, vt.SearchValue, vt.ReplaceValue)
      FROM texts_table AS tt
        JOIN values_table AS vt ON INSTR(tt.Text, vt.SearchValue) > 0
      GROUP BY tt.id
    ;
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2021-11-03
      • 2013-04-09
      • 2015-02-15
      • 1970-01-01
      • 2018-08-02
      • 1970-01-01
      • 1970-01-01
      • 2022-08-17
      相关资源
      最近更新 更多