Вы уверены, что не хотите использовать MySQL полнотекстовый поиск для этого?
Если ответом является «Нет», вы можете продолжить чтение ...
В одном из моих проектов я реализовывал нечто подобное. Запрос выглядит так (упрощенная версия):
SELECT
name
FROM
table
WHERE
name REGEXP 'term1|term2|term3' -- you can use your OR + LIKE way
ORDER BY
SP_TermsWeitght(name, 'term1 term2 term3') DESC
Все маги c находятся в моей функции SP_TermsWieght, которая возвращает «вес» (число), и я предоставляю список терминов (очищено) и нормализовано) к функции.
Функция:
CREATE FUNCTION `SP_TermsWeight`(
`sValue` TEXT,
`sTerms` VARCHAR(127)
)
RETURNS INT
DETERMINISTIC
BEGIN
DECLARE i INT DEFAULT 1;
DECLARE p INT DEFAULT 1;
DECLARE w INT DEFAULT 0;
DECLARE l INT;
DECLARE c CHAR(1);
DECLARE s VARCHAR(63);
DECLARE delimiters VARCHAR(15) DEFAULT ' ,';
SET sTerms = TRIM(sTerms);
SET l = LENGTH(sTerms);
IF (l > 0) THEN
-- checking is value matched terms exactly
IF (sTerms = sValue) THEN
SET w = 50000;
ELSE
-- supposing that "the terms" is one single term so it it match in full, the weight will be high
IF (l <= 63) THEN
SET w = w + SP_TermWeight(sValue, sTerms, 5000, 1000, 100);
END IF;
-- not processing it term by term if it is already matched as full
IF (w = 0) THEN
-- processing term by term using space or comma as delimiter
WHILE i <= l DO
BEGIN
SET c = SUBSTRING(sTerms, i, 1);
IF (LOCATE(c, delimiters) > 0) THEN
SET s = SUBSTRING(sTerms, p, i - p);
SET w = w + SP_TermWeight(sValue, s, 50, 10, 0);
SET p = i + 1;
END IF;
SET i = i + 1;
END;
END WHILE;
IF (p > 1 AND p < i) THEN
SET s = SUBSTRING(sTerms, p, i - 1);
SET w = w + SP_TermWeight(sValue, s, 50, 10, 0);
END IF;
END IF;
END IF;
END IF;
RETURN w;
END
С технической точки зрения это «разделение» терминов с использованием разделителей и проверка, «содержит» ли значение термин. Немного сложно объяснить все, что он делает (я добавил несколько комментариев в код для вас). Не стесняйтесь задавать вопросы, если вы не понимаете некоторые моменты.
В вашем случае это может быть значительно упрощено, поскольку вам не нужно различать начальное / конечное / среднее совпадения.
Еще одна вспомогательная функция, которая используется внутри:
CREATE FUNCTION `SP_TermWeight`(
`sValue` TEXT,
`sTerm` VARCHAR(63),
`iWeightBegin` INT,
`iWeightEnd` INT,
`iWeightMiddle` INT
)
RETURNS INT
DETERMINISTIC
BEGIN
DECLARE r INT DEFAULT 0;
SET sTerm = TRIM(sTerm);
IF (LENGTH(sTerm) > 1) THEN
IF (iWeightBegin != 0 AND sValue REGEXP CONCAT('[[:<:]]', sTerm)) THEN
SET r = r + iWeightBegin;
END IF;
IF (iWeightEnd != 0 AND sValue REGEXP CONCAT(sTerm, '[[:>:]]')) THEN
SET r = r + iWeightEnd;
END IF;
IF (r = 0 AND iWeightMiddle != 0 AND sValue REGEXP sTerm) THEN
SET r = r + iWeightMiddle;
END IF;
END IF;
RETURN r;
END
Эта функция используется для присвоения различных весов, если термин соответствует значению от начала строки, в конце строки или в середине. Это важно в моем случае. В вашем случае это может быть просто как.