Гость
Целевая тема:
Создать новую тему:
Автор:
Форумы / MySQL [игнор отключен] [закрыт для гостей] / Поиск записей при связи многие ко многим / 9 сообщений из 9, страница 1 из 1
12.05.2016, 12:32
    #39234207
Int_20h
Гость
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Поиск записей при связи многие ко многим
Имеется запрос вида
Код: sql
1.
select Goods.* from Goods left join Goods_Categories using (GoodsID)



связь Goods с Categories - многие ко многим через таблицу Goods_Categories

Необходимо отбирать GoodsID, входящие в категории, как по правилу И, так и ИЛИ. Например:

только GoodsID, входящие в категории (2 или 3) и одновременно с этим входящие в категории (5 или 8 или 17) и одновременно в категории (7 или 4).

При таком запросе из таблицы вида:

GoodsID CategoriesID
1 2
1 8
1 4
2 1
2 2
2 6

должен быть отобран только GoodsID = 1. Пока приходит в голову только вложенная структура с кучей объединений, что наверное не правильно.

Код: sql
1.
2.
3.
4.
5.
6.
7.
8.
9.
select * 
from Goods 
where GoodsID in 
  (select GoodsID 
   from Goods_Categories GC1 
    join Goods_Categories GC2 using (GoodsID) 
    join Goods_Categories GC3 using (GoodsID) 
   where GC1.CategoriesID in (2,3) and GC2.CategoriesID in (5,8,17) and GC3.CategoriesID in (7,4)
  )


Сейчас в таблице 17 000 записей. При 3 джоинах они превращаются в 2 509 528. А если таких джоинов будет 5 или 6?!!!

Подскажите, какими методами обычно решают подобные задачи?
...
Рейтинг: 0 / 0
12.05.2016, 15:13
    #39234394
Akina
Участник
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Поиск записей при связи многие ко многим
Такие задачи решают группировкой и пост-отбором по наложенным ограничениям.авторНапример:

только GoodsID, входящие в категории (2 или 3) и одновременно с этим входящие в категории (5 или 8 или 17) и одновременно в категории (7 или 4).
Код: sql
1.
HAVING SUM(category in (2,3)) AND SUM(category in (5,8,17)) AND SUM(category in (4,7)) 
...
Рейтинг: 0 / 0
12.05.2016, 23:51
    #39234751
Int_20h
Гость
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Поиск записей при связи многие ко многим
Akina,

Великолепное решение, спасибо большое. Сейчас еще проверю, будет ли такой запрос кэшироваться.

С одной стороны, насколько я понимаю, HAVING не оптимизируется встроенным оптимизатором, кроме того, запросы с функциями не кэшируются. С другой стороны, функции то простые, на одном и том же наборе данных должны возвращать одинаковые значения.... Может закэшируется, тогда все вообще идеально будет.
...
Рейтинг: 0 / 0
13.05.2016, 06:54
    #39234811
tanglir
Участник
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Поиск записей при связи многие ко многим
Int_20hHAVING не оптимизируется встроенным оптимизатором,во-первых, что там в принципе можно "оптимизировать"?
во-вторых, а разве есть какой-то другой оптимизатор?
...
Рейтинг: 0 / 0
14.05.2016, 23:25
    #39235885
Int_20h
Гость
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Поиск записей при связи многие ко многим
Akina,

Все реализовал, производительность на высоте, спасибо огромное. Но возникла одна сложность, которую пока не знаю, как обойти.

Иногда нужно считать количество товаров в выборке. Раньше я просто делал count в селекте и все:

select count(distinct GoodsGen.GoodsID) from GoodsGen left join GoodsGroups using (GoodsID) left join GoodsCategories using (GoodsID) where GoodsGen.Deleted = 0 and GoodsGen.Archived = 0 and GoodsGroups.GroupsID in (79) group by GoodsGen.GoodsID having SUM(GoodsCategories.CategoriesContentsID in (136)) order by GoodsGen.OrderNum asc

Сейчас же он считает строки внутри Group by и я получаю все строки с единицами. Как лучше обойти данную проблему?
...
Рейтинг: 0 / 0
14.05.2016, 23:28
    #39235886
Int_20h
Гость
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Поиск записей при связи многие ко многим
Запрос с форматированием из предыдущего сообщения
Код: sql
1.
select count(distinct GoodsGen.GoodsID) from GoodsGen left join GoodsGroups using (GoodsID) left join GoodsCategories using (GoodsID) where GoodsGen.Deleted = 0 and GoodsGen.Archived = 0 and GoodsGroups.GroupsID in (79) group by GoodsGen.GoodsID having SUM(GoodsCategories.CategoriesContentsID in (136)) order by GoodsGen.OrderNum asc
...
Рейтинг: 0 / 0
14.05.2016, 23:43
    #39235888
Int_20h
Гость
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Поиск записей при связи многие ко многим
Пока сделал вложенный запрос:

Код: sql
1.
2.
3.
4.
5.
6.
7.
8.
9.
10.
11.
12.
13.
14.
15.
16.
SELECT count( DISTINCT PreSelect.GoodsID )
FROM (
   SELECT GoodsGen.GoodsID AS GoodsID
   FROM GoodsGen
   LEFT JOIN GoodsGroups
   USING ( GoodsID )
   LEFT JOIN GoodsCategories
   USING ( GoodsID )
   WHERE GoodsGen.Deleted =0
   AND GoodsGen.Archived =0
   AND GoodsGroups.GroupsID
   IN ( 79 )
   GROUP BY GoodsGen.GoodsID
   HAVING SUM( GoodsCategories.CategoriesContentsID IN ( 44, 69 ) )
   ORDER BY GoodsGen.OrderNum ASC
) AS PreSelect



Есть ли способы эффективнее?
...
Рейтинг: 0 / 0
15.05.2016, 07:49
    #39235907
MasterZiv
Участник
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Поиск записей при связи многие ко многим
tanglirInt_20hHAVING не оптимизируется встроенным оптимизатором,во-первых, что там в принципе можно "оптимизировать"?
во-вторых, а разве есть какой-то другой оптимизатор?


поддерживаю.
только exist с подзапросом!
...
Рейтинг: 0 / 0
16.05.2016, 06:29
    #39236229
tanglir
Участник
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Поиск записей при связи многие ко многим
Int_20h,

а не проще на клиенте посчитать, сколько строк пришло? лимита в запросе вроде бы нет.
...
Рейтинг: 0 / 0
Форумы / MySQL [игнор отключен] [закрыт для гостей] / Поиск записей при связи многие ко многим / 9 сообщений из 9, страница 1 из 1
Найденые пользователи ...
Разблокировать пользователей ...
Читали форум (0):
Пользователи онлайн (0):
x
x
Закрыть


Просмотр
0 / 0
Close
Debug Console [Select Text]