Получение записей MySQL на основе переменного набора точек сравнения

Допустим, у меня есть таблица MySQL, people. Каждая запись содержит множество свойств, среди которых favourite_colour, country и age_group.

Что я хотел бы сделать, так это получить записи из этой таблицы по их сходству с набором определенных параметров. Например, учитывая «красный», «США» и «18-25», лучшими результатами будут те записи, которые соответствуют всем трем. Это будут 100% совпадения.

Однако я также хотел бы получить записи, которые соответствуют любой комбинации двух параметров (совпадение 66%) или любому одному параметру (совпадение 33%). Кроме того, я хотел бы иметь возможность определять дополнительные точки сравнения (например, underwear_type, marital_status и т. д.).

Есть ли относительно эффективное решение этой проблемы?


person Daniel Wright    schedule 09.06.2009    source источник


Ответы (2)


Да, вы можете преобразовать каждое сравнение, такое как favourite_colour='Red' &c, в значение 0 (ложь) или 1 (истина) - mysql сделает это неявно, но для общности вам может понадобиться CAST( (favourite_colour='Red') AS INTEGER), тогда вы SUM все это, т.е. ,

SELECT
userId,
SUM( (favourite_colour='Red'),
     (country='US'),
     (age_group='18-25') ) AS match_score
FROM people
WHERE match_score >= 2
ORDER BY match_score DESC

сначала даст вам идеальные совпадения, затем 2 из 3; легко обобщить на еще большее количество проверок!-)

person Alex Martelli    schedule 09.06.2009
comment
Это действительно очень хорошая идея. Было бы легко добавить вес и к этому, умножив один из результатов. - person Jani Hartikainen; 09.06.2009
comment
Это действительно отличное решение. Пара замечаний/вопросов: насколько я могу судить, SQL не допускает псевдонимы столбцов (например, match_score) в предложениях WHERE. Кроме того, я не думаю, что SUM() ведет себя так, как предлагает ваш запрос (он не принимает несколько аргументов); Документация MySQL указывает, что SUM() является только функцией агрегирования GROUP BY. Удаление предложения WHERE и замена суммы операторами сложения заставили функцию работать как шарм. - person Daniel Wright; 09.06.2009
comment
@Hoobnium, хорошие моменты - я, по-видимому, придумывал свой собственный слишком разумный диалект SQL как для SUM, так и для WHERE ;-). Спасибо за двойную проверку! - person Alex Martelli; 09.06.2009

Для трех первых легко:

select * from people
where
(case when color = 'Red' then 33 else 0 end + 
case when age_group = '18-25' then 33 else 0 end + 
case when country = 'United States' then 33 else 0 end)>=33

Я не понимаю часть "дополнительные точки сравнения", можете пояснить?

person tekBlues    schedule 09.06.2009
comment
Это не очень удобно или элегантно. - person Artem Russakovskii; 09.06.2009
comment
По сравнению с решением Алекса, я должен согласиться!. Но это работает в любом случае. - person tekBlues; 09.06.2009
comment
Вот почему StackOverflow здесь :), чтобы найти лучшее решение. - person Artem Russakovskii; 09.06.2009
comment
@tekBlues: Под дополнительными точками сравнения я имел в виду, что в будущем я могу добавить другие поля (например, underwear_type) для сравнения. Тогда совпадения будут 25%/50%/75%/100%. - person Daniel Wright; 09.06.2009