MYSQL: Можете ли вы вывести результаты, которые соответствуют 3 из 4 выражений?

Скажем, у меня есть такой запрос:

SELECT * FROM my_table WHERE name = "john doe" AND phone = "8183321234" AND email = "[email protected]" AND address = "330 some lane";

Но скажу, что мне нужно только 3 из 4, чтобы соответствовать, я знаю, что могу написать очень длинный запрос с несколькими OR, но мне было интересно, есть ли для этого функция?

Спасибо.

Ответ 1

SELECT
  * 
FROM 
  my_table 
WHERE 
  CASE WHEN name = "john doe"           THEN 1 ELSE 0 END +
  CASE WHEN phone = "8183321234"        THEN 1 ELSE 0 END +
  CASE WHEN email = "[email protected]" THEN 1 ELSE 0 END +
  CASE WHEN address = "330 some lane"   THEN 1 ELSE 0 END
  >= 3;

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

Ответ 2

Святая чрезмерная сложность, Бэтмен.

SELECT * 
FROM my_table 
WHERE (
    (name = "john doe") +
    (phone = "8183321234") +
    (email = "[email protected]") +
    (address = "330 some lane")
) >= 3;

Ответ 3

То же самое с использованием индексов:

SELECT  *
FROM    (
        SELECT  id
        FROM    (
                SELECT  id
                FROM    mytable _name
                WHERE   name = 'john doe'
                UNION ALL
                SELECT  id
                FROM    mytable _name
                WHERE   phone = '8183321234'
                UNION ALL
                SELECT  id
                FROM    mytable _name
                WHERE   email = "[email protected]"
                UNION ALL
                SELECT  id
                FROM    mytable _name
                WHERE   address = '330 some lane'
                ) q
        GROUP BY 
                id
        HAVING
                COUNT(*) >= 3
        ) di, mytable t
WHERE   t.id = di.id

Подробнее о деталях производительности см. запись в моем блоге.

Ответ 4

Мне нравится конструкция IF:

SELECT * FROM my_table
WHERE
(    IF(name    = 'john doe', 1, 0) +
     IF(phone   = '8183311234', 1, 0) +
     IF(email   = '[email protected]', 1, 0) +
     IF(address = '330 some lane', 1, 0)
) >= 3

Ответ 5

Модифицировать запрос Tomalak немного, чтобы он использовал индексы, если они присутствуют. Хотя, если в каждом поле нет индекса, в любом случае произойдет полное сканирование таблицы.

SELECT
*, 
(
    IF(name="john doe", 1, 0) +
    IF(phone = "8183321234", 1, 0) +
    IF(email = "[email protected]", 1, 0) +
    IF(address = "330 some lane", 1, 0) 
) as matchCount
FROM my_table 
WHERE 
    name = "john doe" OR 
    phone = "8183321234" OR 
    email = "[email protected]" OR 
    address = "330 some lane"
HAVING matchCount >= 3