IdentifiantMot de passe
Loading...
Mot de passe oublié ?Je m'inscris ! (gratuit)
Navigation

Inscrivez-vous gratuitement
pour pouvoir participer, suivre les réponses en temps réel, voter pour les messages, poser vos propres questions et recevoir la newsletter

Langage SQL Discussion :

Bonnes pratiques : table avec rows distincts préalablement connus.


Sujet :

Langage SQL

  1. #1
    Nouveau membre du Club
    Profil pro
    Inscrit en
    Mars 2004
    Messages
    61
    Détails du profil
    Informations personnelles :
    Localisation : Belgique

    Informations forums :
    Inscription : Mars 2004
    Messages : 61
    Points : 34
    Points
    34
    Par défaut Bonnes pratiques : table avec rows distincts préalablement connus.
    Bonjour,

    Voici un exemple simpliflié de mon cas.
    Imaginons une table ACCESS qui contient ces quatres colonnes "id" (number), "create", "update", delete" (boolean). Je connais donc à l'avance le nombre de rows potentiels réellement disctincts, sans prendre en compte l'id. (8 dans ce cas)
    Dans une autre table, en liant l'id d'un user et un id de ACCESS, je peux déterminer facilement les accès pour un user.
    Je me demande quel schéma utiliser et comment utiliser ce schéma pour gérer cela.

    Proposition 1 , je crée un nouveau row dans ACCES à chaque fois que je crée les accès pour un user.
    Inconvénient: je vais au final me retrouver avec énormément de rows identiques dans ACCESS (avec uniquement id qui diffère).

    Proposition 2 , j'imagine un code interprété par l'application pour remplacer ACCESS.
    Exemple: "110" voudrait dire "create TRUE, update TRUE, delete FALSE".
    Dans ce cas, plus besoin de la table ACCESS, j'utiliserai simplement un champ avec le code désiré. Inconvénient: ce n'est pas très lisible pour un humain...

    Proposition 3 , je crée par défaut toutes les possibilités envisageables dans ACCESS, et je lie au user l'id de ACCESS correspondant à la combinaison désirée.
    Inconvénient: il faut remplir au préalable la table ACCESS avec toutes les possibilités possibles (problème minime), puis réussir à lier le user avec la bonne id de ACCESS. Et pour avoir un id facilement utilisable, ça revient rapidement à la proposition 2... je ne suis donc pas sûr que ça apporterait grand chose.

    Selon vous, quelle serait la meilleure manière d'aborder ce genre de cas? Existe-t-il d'autres solutions plus élégantes?

    Merci beaucoup.

  2. #2
    Modérateur

    Avatar de CinePhil
    Homme Profil pro
    Ingénieur d'études en informatique
    Inscrit en
    Août 2006
    Messages
    16 799
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 60
    Localisation : France, Haute Garonne (Midi Pyrénées)

    Informations professionnelles :
    Activité : Ingénieur d'études en informatique
    Secteur : Enseignement

    Informations forums :
    Inscription : Août 2006
    Messages : 16 799
    Points : 34 046
    Points
    34 046
    Billets dans le blog
    14
    Par défaut
    Si un user n'a qu'un seul access, tu peux mettre directement les colonnes create, update et delete dans la table des users.

    Si un user peut avoir plusieurs access, tu auras ce schéma (MCD de la méthode Merise) :
    User -1,n----Avoir----0,n- Access

    Il en découlera les tables suivantes :
    user (u_id...)
    access (a_id, a_create, a_update, a_delete)
    user_access (ua_id_user, ua_id_access)

    Si ces access correspondent à une fonction du logiciel, l'association est probablement ternaire :
    User -1,n----Avoir----0,n- Access
    Fonction -0,n---|

    Ce qui donnerait cette fois les tables :
    user (u_id...)
    access (a_id, a_create, a_update, a_delete)
    fonction (f_id...)
    user_access_fonction (ua_id_user, ua_id_access, ua_id_fonction)

    Mais en réalité comme un utilisateur n'a sans doute qu'un seul accès par fonction, cela peut se simplifier en reportant les colonnes create, update et delete dans la table associative et en refaisant une association binaire :
    User -1,n----Access----0,n- Fonction
    user (u_id...)
    fonction (f_id...)
    access (a_id_user, a_id_fonction, a_create, a_update, a_delete)
    Philippe Leménager. Ingénieur d'étude à l'École Nationale Supérieure de Formation de l'Enseignement Agricole. Autoentrepreneur.
    Mon ancien blog sur la conception des BDD, le langage SQL, le PHP... et mon nouveau blog sur les mêmes sujets.
    « Ce que l'on conçoit bien s'énonce clairement, et les mots pour le dire arrivent aisément ». (Nicolas Boileau)
    À la maison comme au bureau, j'utilise la suite Linux Mageïa !

  3. #3
    Nouveau membre du Club
    Profil pro
    Inscrit en
    Mars 2004
    Messages
    61
    Détails du profil
    Informations personnelles :
    Localisation : Belgique

    Informations forums :
    Inscription : Mars 2004
    Messages : 61
    Points : 34
    Points
    34
    Par défaut
    Merci beaucoup pour la réponse! Ca semble effectivement logique. Je me demande tout de même comment gérer le remplissage de la table acces.

    En reprenant le premier schema proposé : User -1,n----Avoir----0,n- Access
    soit:
    user (u_id...)
    access (a_id, a_create, a_update, a_delete)
    user_access (ua_id_user, ua_id_access)


    Comment remplir "acces"? Si à chaque fois que je crée un user_access, je crée une row dans acces qui correspond au besoin, ma table access va vite grossir de manière inutile.
    Et si je remplis initialement ma table access par toutes les combinaisons possibles, je vais avoir beaucoup de données inutiles (surtout en augmentant le nombre de types d'accès)... et il faudra trouver un moyen de retrouver dans access quel est l'id correspondant!

    Est-ce qu'une bonne façon de faire serait:
    - Select dans acces de l'id qui correspond à la combinaison d'accès dont j'ai besoin.
    -- si il y a un résultat, je l'utilise pour user_access
    -- si il n'y a pas de résultat, je le crée dans acces et j'utilise ce dernier pour user_access?
    Est-ce dommage de perdre un select à chaque fois pour vérifier si la combinaison de droits d'accès existe dans la DB, alors qu'on sait ce que l'on veut insérer?



    Le même problème de redondance se pose également avec le cas simplifié:
    user (u_id,... , a_create, a_update, a_delete)

    Avec simplement trois champs définissant les accès, ça va... mais si on en a une quinzaine, n'est pas dommage de stocker tous les droits là-bas? D'autant plus que de très nombreuses fois, on retrouvera pour différents users des combinaisons identiques... Est-ce plus intéressant d'utiliser une table access qui contiendra chaque combinaison maximum une fois, et à laquelle on fait référence en utilisant l'id d'une combinaison?

  4. #4
    Modérateur

    Avatar de CinePhil
    Homme Profil pro
    Ingénieur d'études en informatique
    Inscrit en
    Août 2006
    Messages
    16 799
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 60
    Localisation : France, Haute Garonne (Midi Pyrénées)

    Informations professionnelles :
    Activité : Ingénieur d'études en informatique
    Secteur : Enseignement

    Informations forums :
    Inscription : Août 2006
    Messages : 16 799
    Points : 34 046
    Points
    34 046
    Billets dans le blog
    14
    Par défaut
    Citation Envoyé par Drag Voir le message
    Je me demande tout de même comment gérer le remplissage de la table acces.

    En reprenant le premier schema proposé : User -1,n----Avoir----0,n- Access
    soit:
    user (u_id...)
    access (a_id, a_create, a_update, a_delete)
    user_access (ua_id_user, ua_id_access)


    Comment remplir "acces"? Si à chaque fois que je crée un user_access, je crée une row dans acces qui correspond au besoin, ma table access va vite grossir de manière inutile.
    Non !
    La table access comprend les 8 cas possibles, comme tu l'avais suggéré.
    Dans ce schéma, chaque utilisateur n'a qu'un seul accès.

    À toi de savoir à quoi correspondent ces accès. S'il s'agit, comme je l'ai supposé, d'accès à des fonctions du logiciel, ou à quelque chose de similaire, prend mon dernier schéma.
    (surtout en augmentant le nombre de types d'accès)
    Dois-je comprendre que tu n'auras pas que create, update et delete ?
    Que ce nombre de paramètres peut augmenter plus tard ? Voire être variable selon l'utilisateur ou le type d'utilisateur ?
    Si c'est ça, c'est plus compliqué. Explique mieux ton besoin réel pour que nous puissions t'aider plus efficacement.

    Est-ce qu'une bonne façon de faire serait:
    - Select dans acces de l'id qui correspond à la combinaison d'accès dont j'ai besoin.
    -- si il y a un résultat, je l'utilise pour user_access
    -- si il n'y a pas de résultat, je le crée dans acces et j'utilise ce dernier pour user_access?
    Est-ce dommage de perdre un select à chaque fois pour vérifier si la combinaison de droits d'accès existe dans la DB, alors qu'on sait ce que l'on veut insérer?
    Tu étais parti sur l'hypothèse qu'il n'y avait que 8 access possibles (3 colonnes booléennes) pour un utilisateur. J'ai du mal à comprendre maintenant de quoi tu parles, surtout qu'on arrive ici dans le domaine du traitement plus que dans celui de la modélisation des données.

    Le même problème de redondance se pose également avec le cas simplifié:
    user (u_id,... , a_create, a_update, a_delete)

    Avec simplement trois champs définissant les accès, ça va... mais si on en a une quinzaine, n'est pas dommage de stocker tous les droits là-bas? D'autant plus que de très nombreuses fois, on retrouvera pour différents users des combinaisons identiques... Est-ce plus intéressant d'utiliser une table access qui contiendra chaque combinaison maximum une fois, et à laquelle on fait référence en utilisant l'id d'une combinaison?
    À toi de définir plus précisément ton besoin et ses évolutions possibles en nombre de paramètres.

    Une autre manière de faire consisterait en effet à revenir à une association n-aire.
    Pour rester dans le domaine des accès aux fonctions d'un logiciel, on peut imaginer le cas général dans lequel certaines fonctions auraient plus de 3 possibilités d'accès (lire, créer, rédiger, modifier, vérifier, approuver, publier, valider...)

    Dans ce cas on pourrait concevoir de cette façon...

    1)
    Règle de gestion :
    Une fonction peut avoir plusieurs droits et un droit peut s'appliquer à plusieurs fonctions.

    MCD :
    Fonction -0,n----Avoir----0,n- Droit

    Tables :
    Fonction (f_id, f_libelle...)
    Droit (d_id, d_libelle...)
    Fonction_Avoir_Droit (fad_id_fonction, fad_id_droit)

    2)
    Règle de gestion :
    Un utilisateur peut accéder à plusieurs fonctions avec un certain droit et un couple (fonction, droit) peut être donné en accès à plusieurs utilisateurs.

    Nous avons cette fois besoin du couple (fonction, droit), il faut donc transformer l'association précédente en entité car dans un MCD, on ne peut pas associer une entité à une association.

    MCD :
    Fonction -0,n----Avoir----(1,1)- Fonction_Droit -(1,1)----Avoir----0,n- Droit
    Utilisateur -1,n----Accéder----0,n----|

    Les cardinalités entre parenthèses signifie une identification relative. L'entité Fonction_Droit n'a pas besoin d'identifiant propre ; son identifiant est composé des identifiants des entités auxquelles elle est liée, comme pour l'association (0,n - 0,n) de tout à l'heure. On va donc simplement renommer la table associative.

    L'entité Utilisateur est bien associée à l'entité Fonction-Droit et non pas à une association.

    Tables :
    Fonction (f_id, f_libelle...)
    Droit (d_id, d_libelle...)
    Fonction_Droit (fd_id_fonction, fd_id_droit)
    Utilisateur (u_id, u_nom...)
    Utilisateur_Acceder_Fonction_Droit (uafd_id_utilisateur, uafd_id_fonction_droit)

    Avec 5 tables, on peut avoir autant de fonctions, de droits, d'utilisateurs que l'on veut et toutes les combinaisons sont possibles.
    Philippe Leménager. Ingénieur d'étude à l'École Nationale Supérieure de Formation de l'Enseignement Agricole. Autoentrepreneur.
    Mon ancien blog sur la conception des BDD, le langage SQL, le PHP... et mon nouveau blog sur les mêmes sujets.
    « Ce que l'on conçoit bien s'énonce clairement, et les mots pour le dire arrivent aisément ». (Nicolas Boileau)
    À la maison comme au bureau, j'utilise la suite Linux Mageïa !

  5. #5
    Nouveau membre du Club
    Profil pro
    Inscrit en
    Mars 2004
    Messages
    61
    Détails du profil
    Informations personnelles :
    Localisation : Belgique

    Informations forums :
    Inscription : Mars 2004
    Messages : 61
    Points : 34
    Points
    34
    Par défaut
    Comme indiqué, j'étais parti d'un exemple simplifié... et visiblement, cette simplification était malvenue, désolé.
    Plutôt que d'avoir 3 champs qui peuvent avoir 2 valeurs, j'utilise concrètement 15 champs qui peuvent valoir 3 valeurs. Si je ne me trompe pas, cela revient à 14.348.907 possibilités, je n'ai pas vraiment envie de toutes les introduire par défaut dans la table des accès, même en l'automatisant...
    Je vais également parler de "fonction", plutôt que d'"accès".


    En ce qui concerne la solution proposée (qui me semble élégante), on rencontrerait ceci:
    - Toutes les fonctions peuvent potentiellement avoir tous les droits. (Ce qui remplit déjà pas mal Fonction_Droit...)
    - Un utilisateur définit obligatoirement un Fonction_Droit pour toutes les fonctions existantes.
    Bref, dans ce cas-ci, on se retrouverait alors avec une table Utilisateur_Acceder_Fonction_Droit surchargée! Je n'ai pas l'impression qu'on gagnerait grand chose...

    Le plus simple reviendrait donc à:
    Utilisateur (u_id, u_nom, ... , fonction1, fonction2, fonction3, ..., fonction15)
    La valeur des fonctions correspond au Droit pour cette fonction. (Pas besoin de faire de lien avec une autre table, ce droit n'étant constitué que d'un champ.)
    C'est lourd, c'est moche, mais ici, c'est le plus approprié, n'est-ce pas?

    J'avoue que je sortirais bien volontiers les fonctions de la table Utilisateurs, simplement pour séparer les concepts, même si ça enfreint les préceptes à suivre en DB. (Serait-ce mal?) Ca donnerait:
    Utilisateur (u_id, u_nom, ... , af_if)
    AccesFonction (af_id, fonction1, fonction2, fonction3, ..., fonction15)
    Dans ce cas, un utilisateur aurait son propre pool de fonctions défini dans AccesFonction... et je ne ferai pas attention au fait que plein de combinaisons identiques apparaissent. (Je suppose qu'actuellement, on peut se permettre d'être moins regardant sur les quantités de stockages pour certaines applications...)
    Je précise que j'essaie de laisser les données facile à lire/utiliser/modifier pour le commun des mortels qui devrait un jour se mettre à l'SQL.


    Quoiqu'il en soit, merci pour les réponses, qui m'aident bien à pousser la réflexion plus loin.

  6. #6
    Modérateur

    Avatar de CinePhil
    Homme Profil pro
    Ingénieur d'études en informatique
    Inscrit en
    Août 2006
    Messages
    16 799
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 60
    Localisation : France, Haute Garonne (Midi Pyrénées)

    Informations professionnelles :
    Activité : Ingénieur d'études en informatique
    Secteur : Enseignement

    Informations forums :
    Inscription : Août 2006
    Messages : 16 799
    Points : 34 046
    Points
    34 046
    Billets dans le blog
    14
    Par défaut
    Citation Envoyé par Drag Voir le message
    Plutôt que d'avoir 3 champs qui peuvent avoir 2 valeurs, j'utilise concrètement 15 champs qui peuvent valoir 3 valeurs. Si je ne me trompe pas, cela revient à 14.348.907 possibilités, je n'ai pas vraiment envie de toutes les introduire par défaut dans la table des accès, même en l'automatisant...
    Ce n'est sans doute pas utile en effet !

    Je vais également parler de "fonction", plutôt que d'"accès".


    En ce qui concerne la solution proposée (qui me semble élégante), on rencontrerait ceci:
    - Toutes les fonctions peuvent potentiellement avoir tous les droits. (Ce qui remplit déjà pas mal Fonction_Droit...)
    Donc inutile de définir une entité/table fonction_droit.
    - Un utilisateur définit obligatoirement un Fonction_Droit pour toutes les fonctions existantes.
    Donc en fait on a la règle de gestion suivante :
    Un utilisateur a accès à toutes les fonctions avec pour chacune un certain droit.

    On a une association ternaire entre utilisateur, fonction et droit :
    Utilisateur -(1,n)----Accéder----(1,n)- Fonction
    Droit -1,n-----------------|

    Les cardinalités minimums côté Utilisateur et Fonction n'ont pas beaucoup d'importance en regard de la règle de gestion. Comme un utilisateur ne pourra avoir qu'un seul droit pour chaque fonction, c'est le couple des identifiants de l'utilisateur et de la fonction qui identifiera l'association Accéder. L'identifiant du droit n'interviendra que comme donnée portée par l'association, donc dans la table sous forme de clé étrangère.

    Ce qui ne donne plus que 4 tables :
    Utilisateur (u_id, u_nom...)
    Fonction (f_id, f_nom...)
    Droit (d_id, d_libelle...)
    Acces (a_id_utilisateur, a_id_fonction, a_id_droit)

    La table Fonction aura 15 lignes puisqu'il y a 15 fonctions.
    La table Droit aura 3 lignes puisqu'il y a, si j'ai bien compris, 3 valeurs possibles de droits.
    La table Utilisateur aura autant de lignes qu'il y aura d'utilisateurs.
    La table Access aura (nb_utilisateurs * nb_fonctions) lignes puisque les droits des utilisateurs sont définis pour toutes les fonctions. Avec 100 utilisateurs, ça ne ferait que 1500 lignes, ce n'est pas beaucoup.

    Il pourrait aussi être économe de grouper les utilisateurs ayant des droits identiques sur les mêmes fonctions. A vous de voir si c'est applicable.


    Le plus simple reviendrait donc à:
    Utilisateur (u_id, u_nom, ... , fonction1, fonction2, fonction3, ..., fonction15)
    La valeur des fonctions correspond au Droit pour cette fonction. (Pas besoin de faire de lien avec une autre table, ce droit n'étant constitué que d'un champ.)
    C'est lourd, c'est moche, mais ici, c'est le plus approprié, n'est-ce pas?
    Ca a surtout le défaut de risquer l'instabilité du modèle dans le temps. Si plus tard viennent s'ajouter d'autres fonctions, il faudra revoir l'ensemble des requêtes car le nombre de colonnes change.

    Je précise que j'essaie de laisser les données facile à lire/utiliser/modifier pour le commun des mortels qui devrait un jour se mettre à l'SQL.
    Le commun des mortel n'a en principe pas à savoir comment sont organisées les données du logiciel qu'il utilise. Au concepteur du logiciel de savoir comment sont structurées les données afin d'intégrer à son programme les bonnes requêtes aux bons endroits pour que le logiciel utilise les données à bon escient et de la façon la plus efficace possible.
    Philippe Leménager. Ingénieur d'étude à l'École Nationale Supérieure de Formation de l'Enseignement Agricole. Autoentrepreneur.
    Mon ancien blog sur la conception des BDD, le langage SQL, le PHP... et mon nouveau blog sur les mêmes sujets.
    « Ce que l'on conçoit bien s'énonce clairement, et les mots pour le dire arrivent aisément ». (Nicolas Boileau)
    À la maison comme au bureau, j'utilise la suite Linux Mageïa !

  7. #7
    Nouveau membre du Club
    Profil pro
    Inscrit en
    Mars 2004
    Messages
    61
    Détails du profil
    Informations personnelles :
    Localisation : Belgique

    Informations forums :
    Inscription : Mars 2004
    Messages : 61
    Points : 34
    Points
    34
    Par défaut
    Vis-à-vis de: Utilisateur (u_id, u_nom, ... , fonction1, fonction2, fonction3, ..., fonction15)
    Ca a surtout le défaut de risquer l'instabilité du modèle dans le temps. Si plus tard viennent s'ajouter d'autres fonctions, il faudra revoir l'ensemble des requêtes car le nombre de colonnes change.
    Effectivement... cependant, parmi les "anciennes" requêtes, seules celles récupérant et traitant tous les droits devront être revues. Dans ce cas, on doit compléter le SELECT pour ajouter les nouvelles fonctionnalités. (Les autres requêtes travaillant sur un set de données bien défini, il ne faudrait pas les retravailler.) Ceci dit, si un nouveau droit doit être traité quelque part, il y a de toute façon une modification à faire dans le programme pour le prendre en compte : dans ce cas, je n'ai pas l'impression que modifier le Select est un réel problème, ça fait partie intégrante de la modification. (Cela est d'autant plus vrai si on est certain que la liste des fonctionnalités n'évoluera presque pas.)


    Avec la solution "une seule table", on obtient un query de ce genre (style Oracle, pourquoi pas). Simple, et on sait dans quel ordre on reçoit les droits.
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    SELECT "fonction1", "fonction2", "fonction9" FROM "User" WHERE "id" = 1
    En utilisant la solution élégante, ça donnerait quelque chose de ce style j'imagine:
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    SELECT f."name", r."value" FROM "Right" r, "Access" a, "Fonction" f
    WHERE a."user" = 1
    AND a."right" = r."id"
    AND a."fonction" = f."id"
    AND (f."name" = 'fonction1' OR f."name" = 'fonction2' OR f."name" = 'fonction9')
    Même si ça reste très basique, c'est tout de même plus complexe. De plus, si on veut faire simple, on est obligé de ramener le couple "nom de la fonction / droit de la fonction" pour le traiter, car on ne sait pas dans quel ordre les droits aux fonctionnalités vont nous revenir. (Ce qui n'est peut-être pas plus mal d'ailleurs... en mettant le résultat dans un map, c'est clair et ça peut éviter de se tromper dans le code lorsqu'on traite les droits.)

    Je sais bien que c'est au concepteur du logiciel de bien faire les choses... mais j'ai l'impression que souvent, les choses se font plus vite et plus facilement quand tout est archi simple... surtout quand c'est un autre que le concepteur qui reprend le boulot.


    Merci encore d'avoir pris le temps de faire des réponses claires et complètes. Après toutes ces explications, je culpabiliserais de prendre la solution "moche". Je vais encore y réfléchir un peu!...

  8. #8
    Modérateur

    Avatar de CinePhil
    Homme Profil pro
    Ingénieur d'études en informatique
    Inscrit en
    Août 2006
    Messages
    16 799
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 60
    Localisation : France, Haute Garonne (Midi Pyrénées)

    Informations professionnelles :
    Activité : Ingénieur d'études en informatique
    Secteur : Enseignement

    Informations forums :
    Inscription : Août 2006
    Messages : 16 799
    Points : 34 046
    Points
    34 046
    Billets dans le blog
    14
    Par défaut
    Je persiste à dire que la "solution élégante" est mieux, et pas seulement parce qu'elle est plus élégante !

    Si je comprends bien ta requête, tu cherches quels sont les droits de l'utilisateur 1 sur les fonctions 1, 2 et 9 ?

    Plusieurs remarques sur ta requête :
    1) Évite d'utiliser les mots du SQL pour nommer tes tables ou tes colonnes.
    RIGHT en est un.

    2) Écris tes jointures selon la syntaxe normalisée depuis 1999 avec l'opérateur JOIN.
    Tu y verras beaucoup plus clair dans tes grosses requêtes et éviteras bien des erreurs.

    3) Plutôt qu'une série de OR dans le WHERE pour la même colonne, utilises IN.

    Voici ta requête récrite, en changeant 'right' par 'droit' :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    SELECT f.name, r.value
    FROM Access a
    INNER JOIN Fonction f ON f.id = a.fonction
    INNER JOIN Droit r ON r.id = a.droit
    WHERE a.user = 1
        AND f.name IN ('fonction1', 'fonction2', 'fonction9')
    Elle n'est pas bien compliquée et fonctionnera pour n'importe quelle fonction, n'importe quel utilisateur et n'importe quel droit.

    Si tu cherches tous les droits d'un utilisateur sur toutes les fonctions, il suffit de supprimer le AND dans le WHERE et ta requête fonctionnera quel que soit le nombre de fonctions. Avec les fonctions en colonnes, tu seras obligé de modifier ton code si tu ajoutes une fonction.

    Bref, il vaut mieux avoir un modèle de données normalisé au maximum.
    Philippe Leménager. Ingénieur d'étude à l'École Nationale Supérieure de Formation de l'Enseignement Agricole. Autoentrepreneur.
    Mon ancien blog sur la conception des BDD, le langage SQL, le PHP... et mon nouveau blog sur les mêmes sujets.
    « Ce que l'on conçoit bien s'énonce clairement, et les mots pour le dire arrivent aisément ». (Nicolas Boileau)
    À la maison comme au bureau, j'utilise la suite Linux Mageïa !

  9. #9
    Nouveau membre du Club
    Profil pro
    Inscrit en
    Mars 2004
    Messages
    61
    Détails du profil
    Informations personnelles :
    Localisation : Belgique

    Informations forums :
    Inscription : Mars 2004
    Messages : 61
    Points : 34
    Points
    34
    Par défaut
    Effectivement, les noms de tables sont hyper mal choisis. ("user" est aussi un mot réservé, et "function" l'aurait été.) C'était juste un test rapide, qui passe en Oracle grâce aux guillemets. Merci pour le conseil d'utilisation de INNER JOIN, ainsi que IN, histoire que j'essaie de les employer systématiquement.

    Cependant, si on prend en compte que:
    - une fonction est définie uniquement par son nom.
    - un droit est défini uniquement par son nom.
    Ne serait-il pas plus adéquat de mettre directement "fonction" et "droit" dans la table Access, et de créer des énumérations sur ces colonnes pour limiter les valeurs possibles? Ce qui donnerait:
    Utilisateur (u_id, u_nom...)
    Acces (a_id_utilisateur, a_fonction, a_droit)
    a_id_fonction pourrait valoir par exemple uniquement "fonction1", "fonction2", ... , "fonction15"
    a_id_droit quant à lui pourrait valoir par exemple uniquement "Allow" et "Deny"

    Ca doit donner l'impression que je tourne autour du pot... mais ce n'est pas du tout le cas! En essayant de mettre en oeuvre le schema proposé plus haut, je me demande sérieusement si ça vaut la peine de créer une table Fonction qui contiendrait par exemple uniquement:
    id - name
    1 - fonction1
    2 - fonction2
    ...
    15 - fonction15

    D'autant plus que ça oblige à mettre en place un mécanisme pour récupérer les id relatifs aux noms de fonctions ou de droits. Si on sait que l'utilisateur a des accès "NoRights" sur "fonction1", c'est plus facile de l'introduire directement dans la DB. C'est l'énumération sur les champs qui garantirait l'intégrité des données. On pourrait utiliser ces termes directement comme id dans les tables Fonction et Droits... mais alors, on se retrouve avec une table mono-colonne, ce qui n'est pas conseillé...

  10. #10
    Modérateur

    Avatar de CinePhil
    Homme Profil pro
    Ingénieur d'études en informatique
    Inscrit en
    Août 2006
    Messages
    16 799
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 60
    Localisation : France, Haute Garonne (Midi Pyrénées)

    Informations professionnelles :
    Activité : Ingénieur d'études en informatique
    Secteur : Enseignement

    Informations forums :
    Inscription : Août 2006
    Messages : 16 799
    Points : 34 046
    Points
    34 046
    Billets dans le blog
    14
    Par défaut
    Citation Envoyé par Drag Voir le message
    Cependant, si on prend en compte que:
    - une fonction est définie uniquement par son nom.
    - un droit est défini uniquement par son nom.
    Ne serait-il pas plus adéquat de mettre directement "fonction" et "droit" dans la table Access, et de créer des énumérations sur ces colonnes pour limiter les valeurs possibles? Ce qui donnerait:
    Utilisateur (u_id, u_nom...)
    Acces (a_id_utilisateur, a_fonction, a_droit)
    a_id_fonction pourrait valoir par exemple uniquement "fonction1", "fonction2", ... , "fonction15"
    a_id_droit quant à lui pourrait valoir par exemple uniquement "Allow" et "Deny"
    En MySQL, il existe le type ENUM qui est en fait réellement un type numérique auquel on affecte pour chaque numéro une valeur. Je ne sais pas s'il existe un mécanisme similaire direct en Oracle.

    Ca doit donner l'impression que je tourne autour du pot...
    Oui un peu ! Disons que tu insistes lourdement...

    En essayant de mettre en oeuvre le schema proposé plus haut, je me demande sérieusement si ça vaut la peine de créer une table Fonction qui contiendrait par exemple uniquement:
    id - name
    1 - fonction1
    2 - fonction2
    ...
    15 - fonction15

    D'autant plus que ça oblige à mettre en place un mécanisme pour récupérer les id relatifs aux noms de fonctions ou de droits. Si on sait que l'utilisateur a des accès "NoRights" sur "fonction1", c'est plus facile de l'introduire directement dans la DB.
    Sauf que si l'opérateur saisit par exemple "NoRigt" (avec une belle faute donc), si je prends le cas de MySQL, c'est la valeur zéro qui sera insérée et non pas un message d'erreur qui sera retourné.
    Bien sûr, il serait possible de prévoir une liste de choix limitée aux énumérations possibles dans l'interface utilisateur mais ça demande à constamment maintenir la liste côté programme et côté BDD alors qu'avec une requête sur la table des droits pour alimenter la liste de choix retournera toujours toutes les valeurs de droits existantes, qul que soit le nombre de droits possibles. De plus, si la saisie ne se fait pas par une liste de choix mais par une zone de saisie textuelle, la tentative d'insertion en BDD d'un droit inexistant fait que le SGBD renverra un message d'erreur qui peut être récupéré et traité par le programme.

    On pourrait utiliser ces termes directement comme id dans les tables Fonction et Droits... mais alors, on se retrouve avec une table mono-colonne, ce qui n'est pas conseillé...
    Et ça ne constituerait pas une clé performante car plus coûteuse qu'un entier auto-incrémenté.

    Les données doivent être normalisées et c'est aux programmes de s'adapter à la structure des données, pas l'inverse !
    Philippe Leménager. Ingénieur d'étude à l'École Nationale Supérieure de Formation de l'Enseignement Agricole. Autoentrepreneur.
    Mon ancien blog sur la conception des BDD, le langage SQL, le PHP... et mon nouveau blog sur les mêmes sujets.
    « Ce que l'on conçoit bien s'énonce clairement, et les mots pour le dire arrivent aisément ». (Nicolas Boileau)
    À la maison comme au bureau, j'utilise la suite Linux Mageïa !

  11. #11
    Nouveau membre du Club
    Profil pro
    Inscrit en
    Mars 2004
    Messages
    61
    Détails du profil
    Informations personnelles :
    Localisation : Belgique

    Informations forums :
    Inscription : Mars 2004
    Messages : 61
    Points : 34
    Points
    34
    Par défaut
    Dans le cas présent, les requêtes à la DB sont créées par l'application, il n'y a pas d'opérateur: il n'y aura donc pas "d'erreur de frappe". C'est clair que ça reste un point faible du programme à surveiller de près... si l'énumération du programme ne colle pas parfaitement avec les valeurs dans la DB, certaines requêtes de sélection pourraient ne pas aboutir, à tort. (Cependant, si le nom du droit demandé n'est pas permis dans la DB, à cause d'enum ou de contraintes, je me demande si il n'y a pas également une erreur qui serait générée et qui pourrait être traitée... je testerai.)
    Pour préciser encore plus, on peut également ajouter qu'actuellement, le code de création des tables SQL est généré par le programme... et les contraintes sur les champs dans la DB sont elles aussi générées automatiquement en fonction des enum du programme, ce qui assure qu'il n'y aura pas d'incohérences programme/DB. (Evidemment, c'est facile tant qu'on ne fait que créer des tables... mais il faudra prévoir un mécanisme qui automatise également les changements...)

    Il est prévu que les fonctionnalités et les droits d'accès soient précisés dans le programme qui interragit avec la DB à l'aide d'énumérations. Il est exact que si cette énumération vient à changer, cela implique deux modifications : un dans l'enum de l'application, l'autre dans les contraintes du champs SQL lié. Cependant, sur des données qui sont vouées à évoluer extrêmement peu souvent, la tâche n'est pas énorme... et le programme connait à tout moment les valeurs possibles. Alors qu'en mettant ces données dans une base de donnée, le programme est obligé de faire des requêtes supplémentaires dans la DB pour connaitre l'énumération des valeurs possibles (ce qui n'est pas forcément un problème). Bref, pour un groupe de données voué à ne (presque) jamais être modifié -encore faut-il pouvoir en être certain...-, créer une nouvelle table dans la DB n'apporte pas grand chose j'ai l'impression.
    Je sais bien que plus c'est normalisé, mieux c'est... mais je n'ai pas écrit le programme à la base, je ne peux pas tout changer, et j'aimerais rester cohérent avec ce qui existe déjà. Actuellement, en ce qui concerne les données qui ne seront pas (ou peu) modifiées, ce sont les énum dans programme qui dictent la marche à suivre, et non les données présentes dans la DB. Je vais essayer de ne pas trop changer la ligne de conduite. Lorsque cela sera intéressant (données qui seront modifiées), j'utiliserai bien évidemment les schémas recommandés ici. Et sinon, je jouerai avec les enums.


    En tout cas, merci d'avoir tenu le coup! Si "j'insistais", c'est vraiment parce que le sujet m'intéresse. A chaque fois les réponses étaient claires et bien expliquées... et je les attendais avec impatience. ;-) Ca m'a permis de bien rafraichir les réflexions "schema DB" dans mon esprit, et j'aurai maintenant plus facile à prendre certaines décisions en mon âme et conscience.


    PS: Je ne pense pas qu'en Oracle il existe un ENUM à proprement parler, mais on peut facilement mettre en place un mécanisme similaire avec un "CONSTRAINT... CHECK...".

+ Répondre à la discussion
Cette discussion est résolue.

Discussions similaires

  1. Réponses: 0
    Dernier message: 10/07/2014, 10h50
  2. [MPD] bonnes pratiques : Table de Jonction & Vues pour un ORM
    Par polopollo dans le forum Schéma
    Réponses: 0
    Dernier message: 26/06/2010, 12h45
  3. bonnes pratiques : Table de Jonction & Vues pour un ORM
    Par polopollo dans le forum Administration
    Réponses: 0
    Dernier message: 26/06/2010, 12h45
  4. Tutorial bonne pratique du programmation avec JAVA
    Par menzlitsh dans le forum Langage
    Réponses: 10
    Dernier message: 02/07/2007, 11h56
  5. [FOREIGN K] Valeur de champ = nom de table. Bonne pratique ?
    Par Seb des Monts dans le forum Langage SQL
    Réponses: 9
    Dernier message: 17/05/2005, 10h56

Partager

Partager
  • Envoyer la discussion sur Viadeo
  • Envoyer la discussion sur Twitter
  • Envoyer la discussion sur Google
  • Envoyer la discussion sur Facebook
  • Envoyer la discussion sur Digg
  • Envoyer la discussion sur Delicious
  • Envoyer la discussion sur MySpace
  • Envoyer la discussion sur Yahoo