Запрос MySQL 4.0 помогает двойному соединению вместо подзапросов - PullRequest
0 голосов
/ 28 января 2009

выберите пользователя, пользователя, группы, пользователя. от пользователей, групп, u2g где users.u = u2g.u и groups.g = u2g.g

, который возвращает такие данные:

user, group, something
----------------------
1   , 3,     a
1   , 5,     b
2   , 3,     c
3   , 3,     d
4   , 5,     e

Теперь я хотел бы ограничить этот запрос таким образом, чтобы он отображал только пользователей, которые оба в группах 3 и 5 - так что он будет возвращать только {1,3, a}, {1 , 5, b} для моего примера данных.

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

edit2: извините, я был введен в заблуждение документацией. MySQL 4.0 не поддерживает подзапросы: (

edit3: Этот SQL будет сгенерирован программно для любого количества групп (ну, до 20 в текущей спецификации), поэтому я бы хотел избежать решений, которые дают мне слишком много дополнительного кодирования. Если решение не будет найдено, я просто изменю итоговую таблицу данных .Net 1.1, но я хотел бы избежать этого, если это возможно.

edit4: есть новая идея? Возможно один без подзапросов, который включает IN (3,5)?

Ответы [ 5 ]

1 голос
/ 30 января 2009

Почему groups используется в запросе? Единственное доступное поле (g) существует в u2g. Я полагаю, что вы, вероятно, тоже захотите вернуть оттуда кучу вещей.

Чтобы получить тот набор результатов, который вы описываете, без использования подзапросов, вы получите настоящий беспорядок: квадратичный взрыв текста запроса!

Вам понадобится что-то следующего вида:

select users.u, groups.g, u2g0.something
from users u, groups g, u2g u2g0, u2g u2g1
where groups.g = 3
     and users.u = u2g0.u
     and u2g0.g = 3
     and users.u = u2g1.u
     and u2g1.g = 5
union all
select users.u, groups.g, u2g1.something
from users u, groups g, u2g u2g0, u2g u2g1
where groups.g = 5
     and users.u = u2g0.u
     and u2g0.g = 3
     and users.u = u2g1.u
     and u2g1.g = 5

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

<% for(int i = 0; i < requiredGroups.Length; i++) { %>
  <% if(i > 0) { %>
    union all
  <% } %>
select users.u, groups.g, u2g<%=i%>.something
from users u, groups g
  <% for(int j = 0; j < requiredGroups.Length; j++) { %>
     , u2g u2g<%=j%>
  <% } %>
where groups.g = <%=requiredGroups[i]%>
  <% for(int j = 0; j < requiredGroups.Length; j++) { %>
     and users.u = u2g<%=j%>.u
     and u2g<%=j>.g = <%=requiredGroups[j]%>
  <% } %>
<% } %>
1 голос
/ 28 января 2009

Довольно отвратительное необщее решение, которое приводит к двум строкам в Oracle:

  select users.u, groups.g
    from   users , groups, u2g, groups g2, u2g u2g2
    where  users.u = u2g.u 
           and users.u = u2g2.u
           and groups.g = u2g.g
           and g2.g = u2g2.g
           and (groups.g in (3,5) and g2.g in (3,5) and groups.g <> g2.g)
           ;
1 голос
/ 28 января 2009

Что-то в этом роде?

select u.[user], g.group
from     u
    inner join ug on ug.userid = u.id   
    inner join g on g.id = ug.groupid
    inner join 
    (
        select ug.userid
        from ug
        where ug.groupid in (1,2)
        group by ug.userid
        having count(*) = 2
    ) sub on sub.userid = u.id

-Edoode

1 голос
/ 28 января 2009

Использование двойного соединения с группами таблиц даст вам правильный результат:

  select u.user, u2g.something 
  from   users 
  INNER JOIN u2g ON users.u = u2g.u
  INNER JOIN groups g1 ON u2g.g = g1.g AND g1.group = 3
  INNER JOIN groups g2 ON u2g.g = g2.g AND g2.group = 5
  /* try this for two rows, one for each group */
  INNER JOIN groups ON u2g.g = groups.g

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

Другой пример (если вы используете тот же идентификатор группы, с которым вы сопоставляете):

SELECT u.uID, gm.something 
FROM cdcms_users u 
inner join cdcms_group_memberships gm1 on gm1.uID = u.uID AND gm1.gID = 32
inner join cdcms_group_memberships gm2 on gm2.uID = u.uID AND gm2.gID = 33
1 голос
/ 28 января 2009
select u.user, g.group, u2g.something 
from users u, groups g, u2g 
where u.user = u2g.user and g.group = u2g.group 
    where exists 
     (select 1 
         from u2g u2g2 
        where u2g2.user=u.user and u2g2.group in(3,5))
...