Подскажите с запросом для выборки из MySQL

stik.name
На сайте с 21.03.2010
Offline
80
887

Задача с выборкой из мускла, есть в бд таблица, в которой один из столбцов имеет значения вроде таких http://cropme.ru/s/f/b/l/3acfd546.png мне нужно сделать выборку по нескольким номерам.

Варианты вроде:

SELECT * FROM `table` WHERE cat LIKE '%10%' or cat LIKE '%25%' or cat LIKE '%27%';
SELECT * FROM `table` WHERE FIND_IN_SET('10', cat) or FIND_IN_SET('25', cat) or FIND_IN_SET('27', cat);

работают не совсем правильно потому как при выборке результаты не сортируются по количеству совпадений от большего к меньшему.

Первый вариант так вообще херня, особенно если ему задать %1%, то искать он мне будет и 1 и 16 и 21 айди, что не нужно.

Есть варианты какой нужно делать запрос для вывода результатов с сортировкой по количеству совпадений от большего к меньшему? То есть при выводе результатов сначала идут строки где совпадают три числа, потом два, следом соответственно одно число. Наиболее релевантные. У меня в примере используется три числа в запросе, но их может быть от 1 до 10 к примеру.

http://stik.name (http://stik.name) - Think different
B
На сайте с 23.05.2001
Offline
195
#1

Сначала надо сделать правильную схему БД, а потом только запросы.

Если в вашем примере показана колонка из таблицы товаров, содержащая ID категорий, в которые товар входит, то нужна промежуточная таблица связи товаров с категориями.

edogs software
На сайте с 15.12.2005
Offline
714
#2
stik.name:
Задача с выборкой из мускла, есть в бд таблица, в которой один из столбцов имеет значения вроде таких http://cropme.ru/s/f/b/l/3acfd546.png мне нужно сделать выборку по нескольким номерам.

Варианты вроде:
SELECT * FROM `table` WHERE cat LIKE '%10%' or cat LIKE '%25%' or cat LIKE '%27%';
SELECT * FROM `table` WHERE FIND_IN_SET('10', cat) or FIND_IN_SET('25', cat) or FIND_IN_SET('27', cat);


работают не совсем правильно потому как при выборке результаты не сортируются по количеству совпадений от большего к меньшему.
Первый вариант так вообще херня, особенно если ему задать %1%, то искать он мне будет и 1 и 16 и 21 айди, что не нужно.

Есть варианты какой нужно делать запрос для вывода результатов с сортировкой по количеству совпадений от большего к меньшему? То есть при выводе результатов сначала идут строки где совпадают три числа, потом два, следом соответственно одно число. Наиболее релевантные. У меня в примере используется три числа в запросе, но их может быть от 1 до 10 к примеру.

По уму - Вам бы базу перестроить.

Но если нужно тупое и не очень быстрое решение (подходит если база небольшая вполне), то как-то так


SELECT id,
ekey,
if(locate(',2,',concat(',',ekey,',')),1,0)+
if(locate(',3,',concat(',',ekey,',')),1,0)+
if(locate(',4,',concat(',',ekey,',')),1,0)
as wght

FROM `tbl`
order by wght desc

Общая мысль - ищите совпадение каждого числа в каждой строке, если находите - присваиваете 1, если нет - присваиваете 0. Сортируете по количеству совпадений (сумме оных).

concat нужен что бы по "1" не искало 16 и 21, тогда озапятив строку с обоих сторон Вы можете искать честные ,1, и найдете только единицы.

Автоматом такой запрос составить несложно, имена полей подставьте свои.

Разработка крупных и средних проектов. Можно с криптой. Разумные цены. Хорошее качество. Адекватный подход.
LovelAss
На сайте с 05.06.2009
Offline
96
#3

SELECT *, `cat` REGEXP '[[:<:]](10)[[:>:]]' AS `c1`, `cat` REGEXP '[[:<:]](25)[[:>:]]' AS `c2`, `cat` REGEXP '[[:<:]](27)[[:>:]]' AS `c3` FROM `table` ORDER BY `c1` + `c2` + `c3` DESC
B
На сайте с 23.05.2001
Offline
195
#4

Напомню на всякий случай:

stik.name:
У меня в примере используется три числа в запросе, но их может быть от 1 до 10 к примеру.

:)

stik.name
На сайте с 21.03.2010
Offline
80
#5

Basilisk, да, таблица связей конечно упростила бы решение задачи, но в данной ситуации нужно решить задачу с уже имеющимися условиями.

edogs:
По уму - Вам бы базу перестроить.
Но если нужно тупое и не очень быстрое решение (подходит если база небольшая вполне), то как-то так


SELECT id,
ekey,
if(locate(',2,',concat(',',ekey,',')),1,0)+
if(locate(',3,',concat(',',ekey,',')),1,0)+
if(locate(',4,',concat(',',ekey,',')),1,0)
as wght

FROM `tbl`
order by wght desc

Общая мысль - ищите совпадение каждого числа в каждой строке, если находите - присваиваете 1, если нет - присваиваете 0. Сортируете по количеству совпадений (сумме оных).
concat нужен что бы по "1" не искало 16 и 21, тогда озапятив строку с обоих сторон Вы можете искать честные ,1, и найдете только единицы.
Автоматом такой запрос составить несложно, имена полей подставьте свои.

Спасибо, наиболее простое и в общем быстрое решение. Вопрос задавался на нескольких форумах, но этот вариант мне кажется наиболее оптимальным. Под разное количество айди просто реализовать составление запроса в рабочем скрипте.

Пытался найти, можно ли ваш запрос в sqlite перевести, но найти нужного решения не смог. Вы не знаете?

LovelAss:
SELECT *, `cat` REGEXP '[[:<:]](10)[[:>:]]' AS `c1`, `cat` REGEXP '[[:<:]](25)[[:>:]]' AS `c2`, `cat` REGEXP '[[:<:]](27)[[:>:]]' AS `c3` FROM `table` ORDER BY `c1` + `c2` + `c3` DESC

Спасибо и Вам, решение по скорости почти такое же как и предыдущее и выборка та же, но визуально и по адаптации понравился больше предыдущий вариант. ;)

edogs software
На сайте с 15.12.2005
Offline
714
#6

stik.name, с sqllite практически не знакомы, но по идее locate можно заменить на like или instr функциями, а вместо if-а использовать case. Но наверняка не уверены.

stik.name
На сайте с 21.03.2010
Offline
80
#7

Понял. Ну решили на этом проекте оставить пока так, с вашим вариантом. А для последующих сейчас делаю таблицу связей.

B
На сайте с 23.05.2001
Offline
195
#8
stik.name:
Понял. Ну решили на этом проекте оставить пока так, с вашим вариантом. А для последующих сейчас делаю таблицу связей.

Отличное решение :)

L
На сайте с 10.02.2015
Offline
121
#9

Если myisam, или версия майскл от 5.6, то FULLTEXT индекс.

Иначе sphinx.

Авторизуйтесь или зарегистрируйтесь, чтобы оставить комментарий