Relation N:M : sélectionner des valeurs, exclure d'autres

Comment jouer aux papous et ne récupérer que les papas, pas ceux à poux

Le problème exposé dans ce sujet a été résolu.

Bonsoir tout le monde

Ces temps, j’ai un peu l’impression de jouer aux papous, avec MySQL. Et je ne m’en sors pas  :D

Dans le cadre d’une organisation avec aussi une structure scolaire, j’ai une base de données où il y a des personnes, ainsi que des rôles possibles pour celles-ci. Parmi ces rôles, il y a Membre et Elève.
En diverses occasions, il faut pouvoir exporter les informations, et c’est là qu’un cas m’étant problématique apparaît : l’export pour l’envoi des bulletins de versement pour les cotisations. Ces cotisations, les membres les doivent, sauf s’il s’agit d’élèves. Il me faut donc les personnes ayant le rôle Membre, mais pas le rôle Elève. Et je n’ai pas tous les cas en tête, mais il risque d’y avoir des cas plus complexes, comme récupérer des personnes ayant deux rôles mais pas deux autres.

Si je n’ai pas trop de peine à imaginer la requête pour sélectionner les membres ayant un ou plusieurs rôles spécifiques (cf. ci-dessous), je ne vois pas comment je peux effectuer l’exclusion de rôle(s) défini(s).

Est-ce que quelqu’un pourrait m’expliquer comment faire ?

Merci d’avance  :)

Récupération naïve des personnes avec l’un ou l’autre rôle voulu
SELECT
        m.*
    FROM
                membre m
        INNER JOIN
                membre_role mr
            ON
                    m.id = mr.membre_id
        INNER JOIN
                role r
            ON
                    mr.role_id = r.id
                AND r.name IN ( les noms des rôles voulus — sans quoi j'aurais omis cette jointure "inutile" )

Plus ou moins lié, est-ce que quelqu’un aurait un exemple d’UI simple et pratique pour proposer ce genre de filtre ? J’avais pensé à une liste de "cases à cocher ternaires", qui me semblait le plus compact, et selon l’affichage, le plus compréhensible. Moins recherché, deux cases à cocher (sélectionné, exclu) avec du JavaScript qui empêche les deux d’être cochées en même temps, mais pas les deux d’être décochées ("pas important"), mais avec une surcouche graphique existante, ce sera probablement mieux. Une version avec trois boutons radio n’irait pas pour les utilisateurs cible — et je ne veux pas de valeur qui dit "on n’a pas choisi ce rôle", dans ce cas, on n’envoie rien.

+0 -0

Un truc qui peut être efficace est d’utiliser (NOT) EXISTS. Donc ça ressemblerait à

SELECT
  m.*
FROM membre m
WHERE
EXISTS (select 1 from membre_role mr JOIN role r ON mr.role_id = r.id WHERE mr.membre_id = m.id AND r.name in (...))
AND NOT EXISTS (select 1 from membre_role mr JOIN role r ON mr.role_id = r.id WHERE mr.membre_id = m.id AND r.name in (...)) 

Plus ou moins lié, est-ce que quelqu’un aurait un exemple d’UI simple et pratique pour proposer ce genre de filtre ? J’avais pensé à une liste de "cases à cocher ternaires", qui me semblait le plus compact, et selon l’affichage, le plus compréhensible. Moins recherché, deux cases à cocher (sélectionné, exclu) avec du JavaScript qui empêche les deux d’être cochées en même temps, mais pas les deux d’être décochées ("pas important"), mais avec une surcouche graphique existante, ce sera probablement mieux.

Ymox

Je suis pas sûr de saisir le besoin exactement.

Tu veux permettre quel genre d’action(s) aux utilisateurs ? Dans le sens, quel(s) objectif(s) ils peuvent chercher à atteindre via cet outil ?

Concrètement, j’aimerais qu’ils puissent choisir d’inclure des rôles et d’en exclure d’autres, tout en ne touchant rien pour ceux qui n’importent pas. Et côté serveur, recevoir les informations que "l’utilisateur aimerait les membres de ce(s) groupe(s) mais pas qui sont aussi de ce(s) groupe(s)-ci".

J’ai déjà quelque chose qui fonctionne en front-end, mais cela utilise un langage écrit et dont je ne vais pas m’aventurer à analyser la syntaxe lors de la réception pour traitement. Pour la requête d’exemple, on aurait "Membre" && !Elèves — les guillemets autour de Membre sont là pour éviter que les personnes avec le rôle "Ancien membre" ne sortent aussi. Peut-être que je pourrais jouer avec la casse pour le front-end, mais pas en back-end.

Edit

Pour deux rôles inclus et deux exclus, cela donnerait ceci avec la syntaxe de l’outil JavaScript : "Membre" or Membre d'honneur && !Elève && !"Ancien membre".

Edit 2

Merci @Migwel, je m’approchais de ça gentiment en expérimentant, mais après avoir pris le temps de bien saisir ce que tu me proposes, c’est plus clair ainsi exposé. J’étais sur le point de te poser une question sur la raison de la présence de jointure dans les sous-requêtes, jusqu’à ce que je perçoive que "sortir la jointure" ne permettrait pas un fonctionnement adéquat.

Edit 3

Par rapport au besoin sur les filtres, peut-être que ce qui n’est pas clair est que les rôles ne s’excluent pas.

Mon souci est que si on demande tous les rôles à l’exception de l’un d’entre eux, une personne ayant ce rôle non choisi en plus d’un de ceux choisis va sortir. Si je demande les membres, tous ceux qui ont le rôle Membre vont sortir, y compris ceux qui ont aussi le rôle Elève. Or, sans même vouloir un ou plusieurs rôles précis (Membre), il est plus facile de dire "j’exclus ceux qui ont le rôle Elève" que "j’aimerais toutes les personnes qui ont au moins un rôle parmi ceux qui ne sont pas le rôle Elève" — outre le fait que la formulation est tarabiscotée. Il me faut à mon avis un moyen pour savoir qu’on ne veut vraiment pas les personnes ayant le rôle Elèves, en plus de savoir qu’on souhaite qu’elles aient d’autres rôles.

Au final, je cherche quelque chose qui pourrait avoir cet aspect-là pour chaque rôle dans le formulaire de filtre, mais qui n’envoie RIEN au serveur lors de la soumission du formulaire quand "la position est sur neutre". La plupart des solutions que j’ai trouvées utilisent trois éléments qui ont chacun leur valeur, et donc il faut filtrer ce qu’on reçoit…

Je mets le sujet comme étant résolu parce que le problème de départ l’est effectivement, cette histoire de widget devrait faire l’objet d’un nouveau sujet, mais vu que j’en ai parlé ici, des réponses sur ce point restent bienvenues.

+0 -0
Connectez-vous pour pouvoir poster un message.
Connexion

Pas encore membre ?

Créez un compte en une minute pour profiter pleinement de toutes les fonctionnalités de Zeste de Savoir. Ici, tout est gratuit et sans publicité.
Créer un compte