2009-07-01 2 views
2

Я внедряю систему ACL для домашнего пива в веб-приложении, и это дает мне трудное время. Я считаю, что это тривиально, я просто не могу обойти его.Trouble with join query

У меня есть 3 таблицы в один ко многим отношений:
resource, perms_group, perms_users где perms_group является ключевой таблицей в то время как perms_users сеточки меня прекрасный доступа мелодии для каждого пользователя, если это необходимо (это добавляет до perms_users или просто переопределяет его, обе таблицы хранят разрешения как логические значения в отдельных столбцах).

Я пытаюсь получить материал с ресурса, а также разрешение Садись в одном запросе:

SELECT * 
FROM resource 
LEFT OUTER JOIN perms_groups ON resource.id = perms_group.res_id 
LEFT OUTER JOIN perms_users ON resource.id = perms_users.res_id 
WHERE resource.id = 1 
    AND perms_group.group_id = 2 
    AND perms_users.user_id = 3 

Теперь беда в том, что штраф разрешения для пользователя устанавливается редко и выше запрос будет возвращать 0 строк в таком дело. То, что я пытаюсь рассказать, это вернуть мне perms для группы 2 и для пользователя 3 , если таковые установлены,. В основном мне не хватает AND_IF_EXISTS оператора;). Я мог бы легко разбить его в двух запросах, но так как он будет работать с обновлением каждой страницы, мне нужно, чтобы он был максимально постным. В настоящее время я использую MySQL, но позже хотел бы перейти на PostgreSQL, поэтому идеальное решение было бы независимым от db. Есть идеи?

Благодаря

ответ

4
SELECT * 
FROM resource 
LEFT OUTER JOIN perms_groups ON resource.id = perms_group.res_id 
          AND perms_group.group_id = 2 
LEFT OUTER JOIN perms_users ON resource.id = perms_users.res_id 
          AND perms_users.user_id = 3 
WHERE resource.id = 1 

В самом деле, левое внешнее соединение бесполезно, если вы пишете условие на столе, когда вы не знаете, если вы будете иметь данные.

0

Вы можете использовать CASE или COALESCE, чтобы реализовать то, что вам нужно, если вы присоедините (слева внешние соединения) свои разрешения в одну строку.

1

вы могли бы попытаться переместить пункт WHERE в объединение для пользователей & групп ...

SELECT * 
FROM resource 
     LEFT OUTER JOIN perms_groups ON resource.id = perms_group.res_id AND perms_group.group_id = 2 
     LEFT OUTER JOIN perms_users ON resource.id = perms_users.res_id AND perms_users.user_id = 3 
WHERE resource.id = 1  
0

Если разрешения пользователя переопределяют разрешения группы, используйте:

SELECT permission 
FROM resource 
JOIN perms_users 
ON  perms_users.res_id = resource.id 
WHERE resource.id = 1 
     AND user_id = 3 
UNION ALL 
SELECT permission 
FROM resource 
LEFT JOIN 
     perms_groups 
ON  perms_group.res_id = resource.id 
     AND group_id = 2 
WHERE resource.id = 1 
LIMIT 1 

Это будет быть более эффективным, так как этот запрос даже не рассмотрит perms_groups, если он найдет запись в perms_users.