SQL текстовый поиск и порядок - PullRequest
2 голосов
/ 17 сентября 2008

У меня есть запрос:

SELECT *
FROM Items
WHERE column LIKE '%foo%'
   OR column LIKE '%bar%'

Как заказать результаты?

Допустим, у меня есть строки, соответствующие 'foo', и строки, которые соответствуют 'bar', но у меня также есть строка с 'foobar'.

Как упорядочить возвращенные строки, чтобы первые результаты соответствовали большему количеству LIKE?

Ответы [ 10 ]

4 голосов
/ 17 сентября 2008

Случай или вид условной конструкции, поддерживаемой вашей СУБД, - это способ сделать это

select *, case when col like '%foo%' and col like '%bar%' then 2 end 
else 1 end as ordcol 
from items 
where col like '%foo%' or col like '%bar%' order by ordcol
2 голосов
/ 17 сентября 2008
SELECT * FROM Items WHERE column LIKE '%foo%' OR column LIKE '%bar%' 
ORDER BY 
(IF(column LIKE '%foo%',1,0) + IF(column LIKE '%bar%',1,0)) 
DESC

Синтаксис для if является

IF ( condition, true_value, false_value )

1 голос
/ 17 сентября 2008
SELECT * FROM Items
WHERE col LIKE '%foo%'
    OR col LIKE '%bar%'
ORDER BY CASE WHEN col LIKE '%foo%' THEN 1
                WHEN col LIKE '%bar%' THEN 2
            END
1 голос
/ 17 сентября 2008

Вы можете использовать UNION:

SELECT * FROM Items WHERE column LIKE '%foo%' AND column LIKE '%bar%'
UNION
SELECT * FROM Items WHERE column LIKE '%foo%' AND NOT (column LIKE '%bar%')
UNION
SELECT * FROM Items WHERE column LIKE '%bar%' AND NOT (column LIKE '%foo%');

Но это может быть плохо с точки зрения производительности. Хуже того, я предполагаю, что вы хотите использовать это для создания поисковой системы, которая сначала дает наиболее значимые результаты, а затем количество слов не ограничивается 2.

В этом случае вы можете создать столбец score, содержащий количество совпадений. Примерно так:

SELECT
    *,
    (IF(column LIKE '%bar%', 1, 0) + IF(column LIKE '%foo%', 1, 0)) AS score
FROM Items
WHERE column LIKE '%foo%' OR column LIKE '%bar%'
ORDER BY score DESC;

Мой SQL немного ржавый, но что-то подобное должно быть возможно по крайней мере в MySQL 5.0. Смотрите также руководство для функции IF: http://dev.mysql.com/doc/refman/5.0/en/control-flow-functions.html

0 голосов
/ 17 сентября 2008

Поскольку ваш запрос в данный момент написан, предложение WHERE не даст вам никакой информации, которая может быть использована для сортировки ваших результатов. Мне нравится идея Брайана ; добавьте постоянный столбец и объедините запросы, и вы можете получить все в одном наборе результатов. Например:

SELECT 1 as rank, * FROM Items WHERE column LIKE '%foo%' AND column LIKE '%bar%'
UNION
SELECT 2 as rank, * FROM Items WHERE column LIKE '%foo%' AND column NOT LIKE '%bar%'
UNION
SELECT 2 as rank, * FROM Items WHERE column LIKE '%bar%' AND column NOT LIKE '%foo%'
ORDER BY rank

Однако, это только даст вам что-то вроде этого:

  • Неупорядоченный набор всех строк, соответствующих foo и match bar
  • , за которым следует (неупорядоченный набор) все строки, которые соответствуют foo или bar, но не обеим (хотя вы можете разбить это на две отдельные группы, используя другую константу в последнем операторе SELECT).

Что может быть именно тем, что вы ищете, но оно не скажет вам, какие строки соответствуют foo три раза, или отсортирует их перед строками, которые содержат только один экземпляр foo. Также все эти НРАВИТСЯ могут стать дорогими. Если вы действительно хотите отсортировать результаты по релевантности (как бы вы это ни определяли), вам лучше использовать полнотекстовый индекс. Если вы используете MS SQL Server, у него есть встроенный сервис, который будет делать это, и есть также сторонние продукты, которые будут делать то же самое.

РЕДАКТИРОВАТЬ: После просмотра всех других ответов (было только два , когда я начал свой - мне, очевидно, придется учиться думать быстрее ;-)) очевидно, что есть несколько способы сделать это, в зависимости от того, что именно вы пытаетесь достичь. Я бы посоветовал вам протестировать и сравнить решения на основе того, как они работают в вашей системе . Я не эксперт по производительности / настройке, но функции, как правило, замедляют работу, особенно если вы сортируете результаты по функциям. Оператор LIKE тоже не обязательно spry. Как разработчик, кажется естественным использовать знакомые конструкции, такие как «IF» и «CASE», но запросы, которые используют больше подхода на основе множеств, обычно имеют лучшую производительность в RDMS. Опять же, YMMV, так что лучше всего проверить, действительно ли вас беспокоит производительность.

0 голосов
/ 17 сентября 2008

Не все СУБД поддерживают операторы IF (или DECODE в Oracle). Если нет, вы можете использовать подзапрос, чтобы определить таблицу "a" и найти всех сотрудников по имени JO SMITH или их комбинацию.

SELECT 
 a.employee_id,
 a.surname,
 sum(a.counter)
FROM

 (SELECT
   employee_id,
   surname,
   1 as counter
  FROM
   MyTable
  WHERE
   surname like '%SMITH%'

  UNION ALL

  SELECT
   employee_id,
   surname,
   1 as counter
  FROM
   MyTable
  WHERE
   surname like '%JO%'
   ) a

GROUP BY 
 a.employee_id,
 a.surname
ORDER BY 3,1,2

Убедитесь, что вы используете UNION ALL, иначе он не будет работать. Также вы можете использовать UPPER (), чтобы сделать поиск не чувствительным к регистру.

0 голосов
/ 17 сентября 2008

2 Запроса:

SELECT * FROM Items WHERE column LIKE '%foo%' AND column LIKE '%bar%';<br/>
SELECT * FROM Items WHERE (column LIKE '%foo%' AND column NOT LIKE '%bar%') OR (column NOT LIKE '%foo%' AND LIKE '%bar%')

(без XOR в SQL)

0 голосов
/ 17 сентября 2008

Возможно, вы захотите попробовать:

SELECT *
FROM Items
WHERE column LIKE '%foo%' OR column LIKE '%bar%'
ORDER BY CASE WHEN column LIKE '%foo%' AND column LIKE '%bar%' THEN 1 ELSE 0 END DESC

Примечание: это сухой код и, вероятно, не очень переносимый.

0 голосов
/ 17 сентября 2008

Попробуйте этот код:

SELECT * FROM Items WHERE column LIKE '%foo%' OR column LIKE '%bar%'
order by (select count(*) from items i where i.column= item.column) DESC 

Вы также можете группировать по column и count(*), а затем ORDER, если вас не волнуют детали.

0 голосов
/ 17 сентября 2008

Какая СУБД?

Это можно сделать, например, через CTE или Union, но если вы используете, например, MySQL, вы можете об этом забыть.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...