2016-05-31 2 views
0

Как заменить значения в SELECT с совпадением текста с строками в другой таблице?MySQL SELECT шаблон заменить на результаты из другой таблицы

**products** 
> +-------+--------------------------------------------------+ 
> | id | description          | 
> +-------+--------------------------------------------------+ 
> | 10001 | This product is %block1% and %block4%   | 
> | 10002 | This product is %block2%, %block3%, and is %block4% | 
> +-------+--------------------------------------------------+ 

**descriptions** 
> +-----------+-------------------+ 
> | blockname | blockcontent  | 
> +-----------+-------------------+ 
> | %block1% | 5 feet tall  | 
> | %block2% | matte white  | 
> | %block3% | makes music  | 
> | %block4% | made of real wood | 
> +-----------+-------------------+ 

В идеале я хотел бы запустить один запрос, который возвращает

> +-------+--------------------------------------------------+ 
> | id | newdescription          | 
> +-------+--------------------------------------------------+ 
> | 10001 | This product is 5 feet tall and made of real wood   | 
> | 10002 | This product is matte white, makes music, and is made of real wood | 
> +-------+--------------------------------------------------+ 

Я исследуемую REPLACE() и подставим(), но они, кажется, не то, что я ищу для.

+1

Это похоже на действительно странный шаблон использования для реляционной базы данных. –

+0

Наша бэкэнд-команда хочет использовать различные блоки в описаниях продуктов (многие продукты будут разделять разные общие блоки). – user3574926

+0

Я понимаю намерение, но обычно можно использовать прикладную логику для применения подстановки шаблона, а не пытаться динамически делать это в базе данных. Я не вижу, как вы собираетесь получить запрос, который делает это в кратчайшие сроки, поэтому вам, вероятно, придется подумать о кэшировании результатов замещения каким-то образом, чтобы обеспечить быстрый поиск. –

ответ

0

Вы можете создать функцию:

DROP FUNCTION my_subst; 
DELIMITER $$ 

CREATE FUNCTION my_subst(str VARCHAR(255)) 
    RETURNS VARCHAR(255) 
BEGIN 
    DECLARE pos1 INT DEFAULT 0; 
    DECLARE pos2 INT DEFAULT 0; 
    DECLARE token VARCHAR(255); 
    DECLARE new_token VARCHAR(255); 

    label1: LOOP 
     SET pos1 = LOCATE('%%',str); 
     IF pos1 = 0 THEN 
      LEAVE label1; 
     END IF; 

     SET pos2 = LOCATE('%%',str,pos1+1); 
     IF pos2 = 0 THEN 
      LEAVE label1; 
     END IF; 

     SET token = SUBSTR(str,pos1,pos2-pos1+2); 

     SELECT blockcontent INTO new_token FROM descriptions WHERE blockname = token; 

     SET str = REPLACE(str,token,new_token); 

    END LOOP label1; 
    RETURN str; 
END; 
$$ 
DELIMITER ; 

, а затем просто использовать эту функцию, чтобы сделать замены.

+0

Прохладный, я никогда раньше не использовал пользовательские функции. Будет ли это быстрее, чем захват всех блоков в отдельном запросе и цикл в PHP? (Я бы так предположил) – user3574926

+0

Это зависит от того, сколько вызовов этой функции ожидается для каждой отображаемой страницы. Если ожидалось тысячи вызовов, может стоить предварительно загрузить таблицу описаний в PHP в некоторых хэшах и делать подстановку в PHP. Если ожидалось только несколько вызовов, пользовательская функция SQL прекрасна. – amaksr

+0

«Быстро» не может быть вашей главной задачей. Вы можете столкнуться с проблемами масштабируемости. Выполняя подстановку в базе данных, вы не пользуетесь реляционными структурами данных - каждый запрос должен многократно вызывать функцию my_subst. Это означает, что ваша база данных будет работать более интенсивно. Вы можете обнаружить, что вы попали в узкую полосу «моя база данных медленно» с меньшим количеством одновременных пользователей, чем если бы вы выполняли подстановку в PHP. И, как правило, проще и дешевле масштабировать веб-серверы, чем база данных. –