Как избежать декартова произведения с внутренними соединениями

Я знаю, что об этом уже спрашивали, но мне трудно это понять. Я редко использую чистый SQL.
У меня есть три таблицы: Session, GroupName и GroupSessionFeedback.

Я присоединяю Session к GroupFeedback в столбце idUser и присоединяю GroupName к Session в столбце idGroup.

Вот мой код SQL:

SELECT s.idSession, 
       g.name, 
       s.Assistant, 
       s.idGroup, 
       s.start, 
       s.end, 
       f.value
  FROM rempad.Session s
 INNER JOIN rempad.GroupSessionFeedback f
    ON s.idUser = f.idUser
 INNER JOIN rempad.GroupName g
    ON s.idGroup = g.idGroup
 WHERE s.start BETWEEN '2013-04-28' AND '2013-05-28'
   AND s.idUser = 22
    OR s.idUser = 23
    OR s.idUser = 24
    OR s.idUser = 26
    OR s.idUser = 27
    OR s.idUser = 28
    OR s.idUser = 42;

Я хочу, чтобы он возвращал уникальный idSessions, но он совпадал с ним несколько раз из-за соединений, и я действительно не знаю, какой другой подход использовать. Я мог бы делать отдельные вызовы в базу данных, но я действительно стараюсь не забивать базу данных, поскольку она и так довольно медленная.

Любые идеи?

заранее спасибо


person Linda Keating    schedule 31.08.2013    source источник
comment
Два момента: вы смешиваете ands и ors. And имеет приоритет над or, в результате чего фильтр start учитывается только для iduser 22. Другие пользователи просто добавляются к результату. См. Mysql или/и приоритет?. Используйте in или заключите все ors в круглые скобки. Второй момент: если производительность не улучшится, вам, вероятно, придется пересмотреть индексы.   -  person Nikola Markovinović    schedule 31.08.2013


Ответы (3)


Я использовал пример на этой странице: запрос SQL, возвращающий декартово произведение в понять это. Честно говоря, я не указал структуру базы данных в своем вопросе. Но проблема заключалась в том, что в каждой из таблиц, к которым я присоединялся, было более одного совпадающего столбца, поэтому мне нужно было отразить это в моих отчетах о присоединении. Вот образец

 INNER JOIN rempad.GroupSessionFeedback f
 ON s.idUser = f.idUser 
 AND s.idSession = f.idSession 
 AND s.idGroup = f.idGroup

Я надеюсь, что это поможет кому-то другому. л

person Linda Keating    schedule 31.08.2013

Попробуйте использовать это:

select {.......}
from session s inner join groupsessionfeedback f inner join groupname g
on s.iduser = f.iduser and s.idgroup = g.idgroup
where {.......}

Я надеюсь, что это решит это. Однако, если в этом запросе нужны какие-либо другие фильтры, сообщите мне.

person Rijul    schedule 31.08.2013
comment
Привет. Спасибо за ваш ответ, но я считаю, что ваше решение по-прежнему дает те же результаты. Это всего лишь два внутренних соединения, написанные с другим синтаксисом, но по сути они все равно будут производить декартово произведение таблиц. Это то, чего я надеюсь избежать. Но спасибо за ответ - person Linda Keating; 31.08.2013

Страдает ли эта версия запроса той же проблемой:

SELECT s.idSession, g.name, s.Assistant, s.idGroup, s.start, s.end, f.value
  FROM rempad.Session s
 INNER JOIN rempad.GroupSessionFeedback f
    ON s.idUser = f.idUser
 INNER JOIN rempad.GroupName g
    ON s.idGroup = g.idGroup
 WHERE s.start BETWEEN '2013-04-28' AND '2013-05-28'
   AND s.idUser in (22, 23, 24, 26, 27, 28, 42);

Если он по-прежнему выдает повторяющиеся результаты, то какими должны быть строки? В конце концов, это решит проблему с несколькими idsession, но не вернет g.name или f.value:

SELECT distinct s.idSession, s.Assistant, s.idGroup, s.start, s.end
  FROM rempad.Session s
 INNER JOIN rempad.GroupSessionFeedback f
    ON s.idUser = f.idUser
 INNER JOIN rempad.GroupName g
    ON s.idGroup = g.idGroup
 WHERE s.start BETWEEN '2013-04-28' AND '2013-05-28'
   AND s.idUser in (22, 23, 24, 26, 27, 28, 42);
person Gordon Linoff    schedule 31.08.2013