2009-07-01 9 views
2

Je suis en train de mettre en place un système ACL d'infusion maison dans une application Web et cela me pose des problèmes. Je crois que c'est insignifiant, mais je n'arrive pas à comprendre.Problème avec la requête de jointure

J'ai 3 tables en relation un à plusieurs:
resource, perms_group, perms_usersperms_group est une table clé en perms_users me permet d'effectuer une belle accès tune base par l'utilisateur si nécessaire (il ajoute à perms_users ou tout simplement le remplace, les deux tables stockent les permissions comme valeurs booléennes dans des colonnes séparées).

Je suis en train de faire des trucs de ressources, ainsi que les autorisations d'entrer en simple requête:

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 

Maintenant problème est que bien l'autorisation pour l'utilisateur sera mis rarement et au-dessus requête renverra 0 lignes dans ce Cas. Ce que j'essaie de dire, c'est de me renvoyer les perms pour le groupe 2 et pour l'utilisateur 3 s'il y en a,. Fondamentalement, il me manque AND_IF_EXISTS opérateur;). Je pourrais le casser dans deux requêtes facilement mais puisqu'il fonctionnera avec chaque actualisation de page j'ai besoin d'aussi mince que possible. Actuellement, j'utilise MySQL mais je voudrais passer à PostgreSQL plus tard, donc la solution idéale serait db indépendante. Des idées?

Merci

Répondre

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 

En fait, joignez-vous à gauche externe ne sert à rien si vous écrivez une condition sur la table quand vous ne savez pas si vous avez des données.

0

Vous pouvez utiliser CASE ou COALESCE pour implémenter ce dont vous avez besoin, si vous joignez (autorisations externes à gauche) vos autorisations dans une ligne.

1

vous pouvez essayer de déplacer la clause WHERE dans la jointure pour les utilisateurs & groupes ...

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

Si vos autorisations utilisateur remplacent les autorisations de groupe, utilisez ceci:

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 

Cette volonté être plus efficace, car cette requête ne recherchera même pas perms_groups s'il trouve un enregistrement dans perms_users.