MySQL: использовать REPLACE с JOIN? - PullRequest
3 голосов
/ 25 декабря 2011

Мне нужно заменить несколько разных слов в текстовом поле.

Значения поиска и замены находятся в другой таблице.

Например, таблица текстов:

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)

Я пробовал несколько разных способов, но не смог заставить его заменить все строки в текстовом поле.

Ответы [ 2 ]

2 голосов
/ 25 декабря 2011

Необходимо указать условие соединения, например, так:

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 .

0 голосов
/ 25 декабря 2011

A JOIN - неправильный подход. Результирующие строки JOIN создаются путем объединения отдельных строк из каждой объединенной таблицы. Это не очень подходит для того, что вы хотите сделать. Для SELECT JOIN в сочетании с GROUP BY имело бы немного больше смысла, хотя в UPDATE нет условия GROUP BY, так что это не вариант.

SQL не предназначен для такого рода манипуляций с текстом. Это должно выполняться языком программирования, а не языком данных.

Для SELECT вы могли бы заставить 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
;
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...