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

Requêtes MySQL Discussion :

Empêcher les doublons


Sujet :

Requêtes MySQL

  1. #1
    Membre éclairé
    Homme Profil pro
    Ingénieur en électrotechnique retraité
    Inscrit en
    Décembre 2008
    Messages
    1 579
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 72
    Localisation : France, Bas Rhin (Alsace)

    Informations professionnelles :
    Activité : Ingénieur en électrotechnique retraité

    Informations forums :
    Inscription : Décembre 2008
    Messages : 1 579
    Points : 804
    Points
    804
    Par défaut Empêcher les doublons
    Bonjour,
    En modification, je veux empêcher les doublons sur les clés primaires ou uniques. Je voudrais trouver un équivalent de INSERT IGNORE INTO avec UPDATE.

    Voici ma requête de base (sans contrôle):
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    		$requete = "
    			UPDATE lst_activites
    			SET designation = :designation
    			WHERE id_abo = :id_abo AND id = :id
    			";
    Cette requête renvoie une erreur fatale 1062 Duplicata du champ 'Accueil de jour' pour la clef 'designation'

    Pour pallier à cet erreur, j'ai testé ceci:
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    		$requete = "
    			UPDATE lst_activites
    			SET designation = :designation
    			WHERE id_abo = :id_abo AND id = :id AND NOT EXISTS(
    				SELECT designation FROM lst_activites WHERE designation = :designation AND id_abo = :id_abo
    				)
    			";
    Ce code entraîne une erreur fatale 1093 You can't specify target table 'lst_activites' for update in FROM clause.
    Je comprends cette erreur mais après plusieurs recherches et essais, je ne m'en sors pas.

    D'après le code trouvé ici: http://eljuky.com/Forum/Base_de_conn...e__6-577-1.htm, j'ai aussi essayé ceci où la table a2 n'est pas trouvée:
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    		$requete = "
    			UPDATE lst_activites
    			INNER JOIN (
    				SELECT id FROM lst_activites, a2
    				WHERE lst_activites.id = a2.id
    				) AS tmp
    			SET designation = :designation
    			WHERE id_abo = :id_abo AND id = :id
    			";

  2. #2
    Expert éminent sénior Avatar de Artemus24
    Homme Profil pro
    Agent secret au service du président Ulysses S. Grant !
    Inscrit en
    Février 2011
    Messages
    6 381
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Paris (Île de France)

    Informations professionnelles :
    Activité : Agent secret au service du président Ulysses S. Grant !
    Secteur : Finance

    Informations forums :
    Inscription : Février 2011
    Messages : 6 381
    Points : 19 064
    Points
    19 064
    Par défaut
    Salut smccbbm.

    J'ai bien compris que vous avez un problème de doublon.
    Vous essayez de mettre à jour une ligne, à partir d'un identifiant, qui par ailleurs, vous pouvez avoir un doublon sur l'index.
    Et il est tout à fait normal d'avoir comme code erreur, un "ERROR 1062 (23000): Duplicate entry '????' for key 'PRIMARY'".

    Question : Que faites-vous si la table n'a pas été mise à jour ?
    Normalement, on test l'existence avant de faire quoi que ce soit. Et si le test vous convient alors votre requête devra mettre à jour la ligne en question.
    Ce que je ne comprends avec votre requête, c'est de ne pas savoir si la mise à jour s'est faite ?

    Pourriez-vous nous donner le descriptif de votre table afin de connaitre les index, clef primaire et clef étrangère ?

    Le manque de précision dans la nature exacte de votre problème, fait que j'ai émis une hypothèse sur l'index. Voici ce que je propose :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
    43
    44
    45
    46
    47
    48
    49
    50
    51
    52
    53
    54
    55
    56
    57
    58
    59
    60
    61
    62
    63
    64
    65
    66
    67
    68
    69
    70
    71
    72
    73
    74
    75
    76
    77
    78
    79
    80
    81
    82
    83
    84
    85
    86
    87
    88
    89
    90
    91
    92
    93
    94
    95
    96
    97
    98
    99
    100
    101
    102
    103
    104
    105
    106
    107
    108
    109
    110
    111
    112
    113
    114
    115
    116
    117
    118
    119
    120
    121
    122
    123
    124
    125
    126
    127
    128
    129
    130
    131
    132
    133
    134
    135
    136
    137
    138
    139
    140
    141
    142
    143
    144
    145
    146
    147
    148
    149
    150
    151
    152
    153
    154
    155
    156
    157
    158
    159
    160
    161
    162
    163
    164
    165
    166
    167
    168
    169
    170
    171
    172
    173
    174
    175
    176
    177
    178
    179
    180
    181
    182
    183
    184
    185
    186
    187
    188
    189
    190
    191
    192
    193
    194
    195
    196
    197
    198
    199
    200
    201
    202
    203
    204
    205
    206
    207
    208
    209
    210
    211
    212
    213
    --------------
    SET AUTOCOMMIT = 0
    --------------
     
    --------------
    START TRANSACTION
    --------------
     
    --------------
    SET collation_connection = latin1_general_ci
    --------------
     
    --------------
    DROP DATABASE IF EXISTS `base`
    --------------
     
    --------------
    CREATE DATABASE `base`
        DEFAULT CHARACTER SET `latin1`
        DEFAULT COLLATE       `latin1_general_ci`
    --------------
     
    --------------
    DROP TABLE IF EXISTS `lst_activites`
    --------------
     
    --------------
    CREATE TABLE `lst_activites`
    ( `id`            integer UNSIGNED NOT NULL AUTO_INCREMENT,
      `id_abo`        integer UNSIGNED NOT NULL,
      `designation`   varchar(255)     NOT NULL,
      primary key (`id`),
      unique index `idx` (`id_abo`,`designation`)
    ) ENGINE=InnoDB
      DEFAULT CHARSET=`latin1` COLLATE=`latin1_general_ci`
      ROW_FORMAT=COMPRESSED
    --------------
     
    --------------
    insert into `lst_activites` (`id_abo`,`designation`)  values
      (333, 'un'),(555, 'deux'),(777, 'trois'),(555, 'quatre')
    --------------
     
    --------------
    select * from lst_activites order by id
    --------------
     
    +----+--------+-------------+
    | id | id_abo | designation |
    +----+--------+-------------+
    |  1 |    333 | un          |
    |  2 |    555 | deux        |
    |  3 |    777 | trois       |
    |  4 |    555 | quatre      |
    +----+--------+-------------+
    --------------
    update  `lst_activites`
       set  designation = 'quatre'
     where  id     = 2
       and  id_abo = 555
    --------------
     
    ERROR 1062 (23000) at line 51: Duplicata du champ '555-quatre' pour la clef 'idx'
    --------------
    select * from lst_activites order by id
    --------------
     
    +----+--------+-------------+
    | id | id_abo | designation |
    +----+--------+-------------+
    |  1 |    333 | un          |
    |  2 |    555 | deux        |
    |  3 |    777 | trois       |
    |  4 |    555 | quatre      |
    +----+--------+-------------+
    --------------
    update  `lst_activites`
       set  designation = @designation
     where  id     = 2
       and  id_abo = 555
       and  not exists (
     
        select  1
          from  `lst_activites`
         where  designation = 'quatre'
           and  id_abo      = 555
    )
    --------------
     
    ERROR 1093 (HY000) at line 62: You can't specify target table 'lst_activites' for update in FROM clause
    --------------
    select * from lst_activites order by id
    --------------
     
    +----+--------+-------------+
    | id | id_abo | designation |
    +----+--------+-------------+
    |  1 |    333 | un          |
    |  2 |    555 | deux        |
    |  3 |    777 | trois       |
    |  4 |    555 | quatre      |
    +----+--------+-------------+
    --------------
    update  `lst_activites`
       set  designation = 'quatre'
     where  id     = 2
       and  id_abo = 555
       and  not exists (
     
        select  1
          from  ( select  1
                    from  `lst_activites`
                   where  designation = 'quatre'
                     and  id_abo      = 555
                ) as x
    )
    --------------
     
    --------------
    select * from lst_activites order by id
    --------------
     
    +----+--------+-------------+
    | id | id_abo | designation |
    +----+--------+-------------+
    |  1 |    333 | un          |
    |  2 |    555 | deux        |
    |  3 |    777 | trois       |
    |  4 |    555 | quatre      |
    +----+--------+-------------+
    --------------
    update  `lst_activites`
       set  designation = 'cinq'
     where  id     = 2
       and  id_abo = 555
       and  not exists (
     
        select  1
          from  ( select  1
                    from  `lst_activites`
                   where  designation = 'cinq'
                     and  id_abo      = 555
                ) as x
    )
    --------------
     
    --------------
    select * from lst_activites order by id
    --------------
     
    +----+--------+-------------+
    | id | id_abo | designation |
    +----+--------+-------------+
    |  1 |    333 | un          |
    |  2 |    555 | cinq        |
    |  3 |    777 | trois       |
    |  4 |    555 | quatre      |
    +----+--------+-------------+
    --------------
    update           `lst_activites`   as  t1
    left outer join  `lst_activites`   as  t2
                 on  t2.designation = 'quatre'
                and  t2.id_abo      = 555
     
                set  t1.designation = 'quatre'
              where  t1.id          = 2
                and  t2.designation is null
    --------------
     
    --------------
    select * from lst_activites order by id
    --------------
     
    +----+--------+-------------+
    | id | id_abo | designation |
    +----+--------+-------------+
    |  1 |    333 | un          |
    |  2 |    555 | cinq        |
    |  3 |    777 | trois       |
    |  4 |    555 | quatre      |
    +----+--------+-------------+
    --------------
    update           `lst_activites`   as  t1
    left outer join  `lst_activites`   as  t2
                 on  t2.designation = 'six'
                and  t2.id_abo      = 555
     
                set  t1.designation = 'six'
              where  t1.id          = 2
                and  t2.designation is null
    --------------
     
    --------------
    select * from lst_activites order by id
    --------------
     
    +----+--------+-------------+
    | id | id_abo | designation |
    +----+--------+-------------+
    |  1 |    333 | un          |
    |  2 |    555 | six         |
    |  3 |    777 | trois       |
    |  4 |    555 | quatre      |
    +----+--------+-------------+
    --------------
    COMMIT
    --------------
     
    --------------
    SET AUTOCOMMIT = 1
    --------------
     
    Appuyez sur une touche pour continuer...
    J'ai reproduis dans les deux premières requêtes, les mêmes erreurs.

    Dans la troisième et quatrième requête, je vous donne la solution qui vous manque, à savoir comment tester l'existence d'une ligne sur la même table.
    Deux exemples, l'un où il y a doublon et l'autre sans.

    Dans la cinquième et sixième requête, la solution que je préfère.
    Deux exemples aussi, l'un où il y a doublon et l'autre sans.

    Cet exemple n'est pas exhaustif et l'on peut trouver d'autres façons de procéder.

    @+
    Si vous êtes de mon aide, vous pouvez cliquer sur .
    Mon site : http://www.jcz.fr

  3. #3
    Membre éclairé
    Homme Profil pro
    Ingénieur en électrotechnique retraité
    Inscrit en
    Décembre 2008
    Messages
    1 579
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 72
    Localisation : France, Bas Rhin (Alsace)

    Informations professionnelles :
    Activité : Ingénieur en électrotechnique retraité

    Informations forums :
    Inscription : Décembre 2008
    Messages : 1 579
    Points : 804
    Points
    804
    Par défaut
    Bonjour et merci.
    C'est vrai, je n'ai pas été assez clair.
    J'avais répondu trop précipitamment alors je mets ma réponse en attente.

  4. #4
    Modérateur
    Avatar de escartefigue
    Homme Profil pro
    bourreau
    Inscrit en
    Mars 2010
    Messages
    10 136
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Loir et Cher (Centre)

    Informations professionnelles :
    Activité : bourreau
    Secteur : Finance

    Informations forums :
    Inscription : Mars 2010
    Messages : 10 136
    Points : 38 561
    Points
    38 561
    Billets dans le blog
    9
    Par défaut
    Citation Envoyé par smccbbm Voir le message
    En modification, je veux empêcher les doublons sur les clés primaires ou uniques. Je voudrais trouver un équivalent de INSERT IGNORE INTO avec UPDATE.
    bonjour,
    votre problème n'est pas clair : une clef primaire est par définition unique, donc que ce soit clef primaire ou autre clef unique, vous n'aurez jamais de doublon, c'est le SGBD qui le vérifie.

    Citation Envoyé par smccbbm Voir le message
    Voici ma requête de base (sans contrôle):
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    		$requete = "
    			UPDATE lst_activites
    			SET designation = :designation
    			WHERE id_abo = :id_abo AND id = :id
    			";
    Cette requête renvoie une erreur fatale 1062 Duplicata du champ 'Accueil de jour' pour la clef 'designation'
    Ce qui signifie que vous avez défini un index unique sur une zone désignation
    Voilà un choix étrange et dangereux
    Communiquez le DDL de vos tables et index (CREATE TABLE, CREATE INDEX...) afin d'obtenir une réponse pertinente

  5. #5
    Expert éminent sénior Avatar de Artemus24
    Homme Profil pro
    Agent secret au service du président Ulysses S. Grant !
    Inscrit en
    Février 2011
    Messages
    6 381
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Paris (Île de France)

    Informations professionnelles :
    Activité : Agent secret au service du président Ulysses S. Grant !
    Secteur : Finance

    Informations forums :
    Inscription : Février 2011
    Messages : 6 381
    Points : 19 064
    Points
    19 064
    Par défaut
    Salut Escartefigue.

    Oui, en effet, sur une clef primaire ou un index unique, on ne peut pas avoir un doublon.
    En fait, le doublon dont parle smccbbm se manifeste au moment de la modification de la ligne par une erreur 1062, que j'ai reproduit dans mon exemple.

    A priori, je pense qu'il a un index unique sur (`id_abo`,`designation`).
    Par exemple, il a les couples (555 ; deux) pour l'identifiant id=2 et (555 ; deux) pour l'identifiant id=4.
    Jusque là, pas de doublons !

    Il désire modifier la ligne id=2, en remplaçant "désignation" contenant "deux" par "quatre".
    Et c'est là que le doublon se manifeste par l'erreur 1062.

    J'ai plusieurs questions qui me viennent à l'esprit :

    1) pourquoi ne veut-il pas tester l'existence de son doublon avant de faire la modification dans la base de données ?

    2) est-il pertinent de créer un index unique sur le couple (`id_abo`,`designation`) ?

    3) la réponse qu'il demande est d'ignorer l'erreur ???
    C'est contraire au bon fonctionnement d'un script qui doit contrôler les mises à jour.
    Et si la mise à jour ne se fait, qu'est-ce que cela a comme impact sur le traitement ?

    4) mettre une chaîne de caractères dans un index n'est pas très pertinent.
    En général, les chaînes de caractères sont de types informationnelles.
    N'y aurait-il pas un problème de modélisation de la base de données ?

    5) n'y aurait-il pas un problème fonctionnel dans la façon de gérer ses tables ?

    @+
    Si vous êtes de mon aide, vous pouvez cliquer sur .
    Mon site : http://www.jcz.fr

  6. #6
    Membre éclairé
    Homme Profil pro
    Ingénieur en électrotechnique retraité
    Inscrit en
    Décembre 2008
    Messages
    1 579
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 72
    Localisation : France, Bas Rhin (Alsace)

    Informations professionnelles :
    Activité : Ingénieur en électrotechnique retraité

    Informations forums :
    Inscription : Décembre 2008
    Messages : 1 579
    Points : 804
    Points
    804
    Par défaut
    Bonjour et merci à vous deux,

    Je crois que Artemus24 a bien compris mon problème. J'essaye de récapituler.

    Je travaille avec php/PDO.
    Je ne veux pas avoir deux désignations identiques pour le même abonné. J'ai donc bien un index unique pour le couple id_abo/designation.

    1) pourquoi ne veut-il pas tester l'existence de son doublon avant de faire la modification dans la base de données ?
    Parce que j'ai lu que le temps de traitement était plus long. Est-ce vrai? Si c'est mieux, pourquoi pas.

    2) est-il pertinent de créer un index unique sur le couple (`id_abo`,`designation`) ?
    Oui, puisque c'est ce couple qui doit être unique.

    3) la réponse qu'il demande est d'ignorer l'erreur ???
    C'est contraire au bon fonctionnement d'un script qui doit contrôler les mises à jour.
    Et si la mise à jour ne se fait, qu'est-ce que cela a comme impact sur le traitement ?
    Je la contrôle en php à partir du résultat. Là encore, je suis prêt à me remettre en cause.

    4) mettre une chaîne de caractères dans un index n'est pas très pertinent.
    En général, les chaînes de caractères sont de types informationnelles.
    N'y aurait-il pas un problème de modélisation de la base de données ?
    Il s'agit de définition courtes et peu nombreuses pour un même abonné (id_abo). Ce n'est pas absolu, car on est pas à l'abri de modifications légères d'un libellé, mais je ne vois pas d'autres solutions.

    5) n'y aurait-il pas un problème fonctionnel dans la façon de gérer ses tables ?
    Je ne pense pas. J'ai une table de personnes, une table d'activités (celle dont on parle ici), et une table qui relie les deux avec les colonnes id_ind, id_act qui a elles deux constituent un index unique.

    Je ne suis pas figé sur une solution (surtout si elle est mauvaise) mais je suis au contraire en quête de conseils.

  7. #7
    Expert éminent sénior Avatar de Artemus24
    Homme Profil pro
    Agent secret au service du président Ulysses S. Grant !
    Inscrit en
    Février 2011
    Messages
    6 381
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Paris (Île de France)

    Informations professionnelles :
    Activité : Agent secret au service du président Ulysses S. Grant !
    Secteur : Finance

    Informations forums :
    Inscription : Février 2011
    Messages : 6 381
    Points : 19 064
    Points
    19 064
    Par défaut
    Salut smccbbm.

    Citation Envoyé par smccbbm
    J'ai donc bien un index unique pour le couple id_abo/designation.
    En voulant reproduire votre problème, j'avais un doute sur l'usage de vos index.
    Vous me confirmez que je ne me suis pas trompé.

    Citation Envoyé par smccbbm
    Parce que j'ai lu que le temps de traitement était plus long.
    Il faudra détailler ce que vous entendez par "plus long" ?

    Vous avez parlé d'un problème, ce dont j'ai tenté de résoudre.
    Mais ce que j'ignore, c'est dans quel contexte, pour quel usage ?
    Est-ce pour un traitement de masse ou un traitement interactif ?

    Citation Envoyé par smccbbm
    Je la contrôle en php à partir du résultat.
    De quel résultat parlez-vous ?

    On va partir sur un traitement interactif.
    Un utilisateur demande à modifier la colonne "désignation".
    Il saisie une nouvelle valeur et le traitement va modifier la colonne.
    Dans certain cas, la colonne a été mise à jour (unicité au niveau de l'index) et dans d'autres cas, elle ne l'a pas été (cas du doublon).

    Comment faites-vous la distinction entre une modification effectuée et une modification rejetée, car dans les deux cas, le code retour est à zéro ?

    Citation Envoyé par smccbbm
    Ce n'est pas absolu, car on est pas à l'abri de modifications légères d'un libellé, mais je ne vois pas d'autres solutions.
    Si j'interprète votre pensé, vous avez créé un index pour tester l'unicité du couple (id_abo ; designation). Est-ce bien cela ?
    Par ailleurs, cet index ne vous sert rien, même pas pour une question de performance.

    Citation Envoyé par smccbbm
    Je ne pense pas.
    Qu'est-ce que vous en savez ?

    Citation Envoyé par smccbbm
    J'ai une table de personnes, une table d'activités (celle dont on parle ici), et une table qui relie les deux avec les colonnes id_ind, id_act qui a elles deux constituent un index unique.
    La table personnes et la table activités sont des tables mères.
    La troisième table est une table associative, où vous créez des clefs étrangères en relation avec vos tables mères.
    De part ce choix les colonnes id_ind et id_act sont des clefs primaires dans vos tables mères.

    Il me semble que vous avez un problème avec cette table activité, car son organisation n'est pas atomique.
    Je dis cela car vous avez un index qui force à rendre un couple de colonnes unique.

    Vous devez décomposer cette table en deux tables, afin d'extérioriser tout ce qui n'est pas atomique.

    Comme Escartefigue, et afin de poursuivre cette analyse, il nous faut le descriptif (DDL) de vos tables afin de comprendre la nature de votre problème.
    Un jeu d'essai parlant aussi serait le bien venu ! Sans cela, on parle dans le vide.

    @+
    Si vous êtes de mon aide, vous pouvez cliquer sur .
    Mon site : http://www.jcz.fr

  8. #8
    Membre éclairé
    Homme Profil pro
    Ingénieur en électrotechnique retraité
    Inscrit en
    Décembre 2008
    Messages
    1 579
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 72
    Localisation : France, Bas Rhin (Alsace)

    Informations professionnelles :
    Activité : Ingénieur en électrotechnique retraité

    Informations forums :
    Inscription : Décembre 2008
    Messages : 1 579
    Points : 804
    Points
    804
    Par défaut
    Bonsoir et encore merci.

    Le principe:
    L'utilisateur définit des activités dans la table lst_activites,
    Il définit des personnes dans la table dat_individus,
    Il peut alors affecter des activités à chaque individus via la table dat_liens_act

    Voici mes tables exportées à partir de phpMyAdmin:
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
    43
    44
    45
    46
    47
    48
    49
    50
    51
    52
    53
    54
    55
    56
    57
    58
    59
    60
    61
    62
    63
    64
    65
    66
    67
    68
    69
    -- phpMyAdmin SQL Dump
    -- version 4.5.5.1
    -- <a href="http://www.phpmyadmin.net" target="_blank">http://www.phpmyadmin.net</a>
    --
    -- Client :  127.0.0.1
    -- Généré le :  Sam 05 Novembre 2016 à 17:55
    -- Version du serveur :  5.7.11
    -- Version de PHP :  7.0.4
     
    SET SQL_MODE = "NO_AUTO_VALUE_ON_ZERO";
    SET time_zone = "+00:00";
     
     
    /*!40101 SET @OLD_CHARACTER_SET_CLIENT=@@CHARACTER_SET_CLIENT */;
    /*!40101 SET @OLD_CHARACTER_SET_RESULTS=@@CHARACTER_SET_RESULTS */;
    /*!40101 SET @OLD_COLLATION_CONNECTION=@@COLLATION_CONNECTION */;
    /*!40101 SET NAMES utf8mb4 */;
     
    --
    -- Base de données :  `sirap`
    --
     
    -- --------------------------------------------------------
     
    --
    -- Structure de la table `lst_activites`
    --
     
    CREATE TABLE `lst_activites` (
      `id` int(10) UNSIGNED NOT NULL,
      `id_abo` int(10) UNSIGNED NOT NULL,
      `designation` varchar(50) NOT NULL
    ) ENGINE=InnoDB DEFAULT CHARSET=utf8;
     
    --
    -- Contenu de la table `lst_activites`
    --
     
    INSERT INTO `lst_activites` (`id`, `id_abo`, `designation`) VALUES
    (1, 1, 'Accueil de jour'),
    (3, 1, 'Accueil de nuit'),
    (6, 1, 'Conseil d\'administration'),
    (2, 1, 'Manutention'),
    (5, 1, 'Vente braderie'),
    (4, 1, 'Vente magasin');
     
    --
    -- Index pour les tables exportées
    --
     
    --
    -- Index pour la table `lst_activites`
    --
    ALTER TABLE `lst_activites`
      ADD PRIMARY KEY (`id`),
      ADD UNIQUE KEY `designation` (`id_abo`,`designation`) USING BTREE;
     
    --
    -- AUTO_INCREMENT pour les tables exportées
    --
     
    --
    -- AUTO_INCREMENT pour la table `lst_activites`
    --
    ALTER TABLE `lst_activites`
      MODIFY `id` int(10) UNSIGNED NOT NULL AUTO_INCREMENT, AUTO_INCREMENT=7;
    /*!40101 SET CHARACTER_SET_CLIENT=@OLD_CHARACTER_SET_CLIENT */;
    /*!40101 SET CHARACTER_SET_RESULTS=@OLD_CHARACTER_SET_RESULTS */;
    /*!40101 SET COLLATION_CONNECTION=@OLD_COLLATION_CONNECTION */;
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
    43
    44
    45
    46
    47
    48
    49
    50
    51
    52
    53
    54
    55
    56
    57
    58
    59
    60
    61
    62
    63
    64
    65
    66
    67
    68
    69
    70
    71
    72
    73
    74
    75
    76
    77
    78
    79
    80
    81
    82
    83
    84
    85
    86
    87
    88
    89
    90
    91
    92
    93
    94
    95
    96
    97
    98
    99
    100
    101
    102
    103
    104
    105
    106
    107
    108
    109
    -- phpMyAdmin SQL Dump
    -- version 4.5.5.1
    -- <a href="http://www.phpmyadmin.net" target="_blank">http://www.phpmyadmin.net</a>
    --
    -- Client :  127.0.0.1
    -- Généré le :  Sam 05 Novembre 2016 à 17:54
    -- Version du serveur :  5.7.11
    -- Version de PHP :  7.0.4
     
    SET SQL_MODE = "NO_AUTO_VALUE_ON_ZERO";
    SET time_zone = "+00:00";
     
     
    /*!40101 SET @OLD_CHARACTER_SET_CLIENT=@@CHARACTER_SET_CLIENT */;
    /*!40101 SET @OLD_CHARACTER_SET_RESULTS=@@CHARACTER_SET_RESULTS */;
    /*!40101 SET @OLD_COLLATION_CONNECTION=@@COLLATION_CONNECTION */;
    /*!40101 SET NAMES utf8mb4 */;
     
    --
    -- Base de données :  `sirap`
    --
     
    -- --------------------------------------------------------
     
    --
    -- Structure de la table `dat_individus`
    --
     
    CREATE TABLE `dat_individus` (
      `id` int(10) UNSIGNED NOT NULL,
      `id_abo` int(10) UNSIGNED NOT NULL,
      `nom` varchar(50) NOT NULL,
      `prenom` varchar(50) DEFAULT NULL,
      `courriel` varchar(60) DEFAULT NULL,
      `tel1` varchar(20) DEFAULT NULL,
      `tel2` varchar(20) DEFAULT NULL,
      `adr1` varchar(30) DEFAULT NULL,
      `adr2` varchar(30) DEFAULT NULL,
      `cp` varchar(5) DEFAULT NULL,
      `ville` varchar(20) DEFAULT NULL,
      `pays` enum('de','fr','uk') NOT NULL DEFAULT 'fr',
      `statut` varchar(1) DEFAULT NULL,
      `sexe` varchar(1) DEFAULT NULL,
      `commentaires` text NOT NULL,
      `copies` tinyint(1) DEFAULT NULL COMMENT AS `Destinataire des copies des message envoyés par le site`
    ) ENGINE=InnoDB DEFAULT CHARSET=utf8 COMMENT='Les individus peuvent être des salariés ou des bénévoles.';
     
    --
    -- Contenu de la table `dat_individus`
    --
     
    INSERT INTO `dat_individus` (`id`, `id_abo`, `nom`, `prenom`, `courriel`, `tel1`, `tel2`, `adr1`, `adr2`, `cp`, `ville`, `pays`, `statut`, `sexe`, `commentaires`, `copies`) VALUES
    (2, 1, 'Demo', 'Jean', '', '', NULL, '', '', '', '', 'fr', 'c', 'm', '', NULL),
    (3, 1, 'Demo', 'Marie', '', '', NULL, '', '', '', '', 'fr', 'c', 'f', '', NULL),
    (6, 1, 'Bert', 'Gilles', 'info.gilbert@wanadoo.fr', '', NULL, '', '', '', '', 'fr', 'b', 'm', '', NULL),
    (7, 1, 'Hiète', 'Jules', '', '', NULL, '', '', '', '', 'fr', 's', 'm', '', NULL),
    (8, 1, 'Hesse', 'Hardy', '', '', NULL, '', '', '', '', 'fr', 'b', 'm', '', NULL),
    (9, 1, 'Liment', 'Al', '', '', NULL, '', '', '', '', 'fr', 's', 'm', '', NULL),
    (10, 1, 'Croche', 'Annie', 'annie.croche@orange.fr', '', NULL, '12 rue des Petits Oiseaux', 'Villa "Bucolique"', '01000', 'Bourg en Bresse', 'fr', 'b', 'f', '', NULL),
    (11, 1, 'Laud', 'Ange', '', '', NULL, 'Résidence "Bleu Ciel"', '14 rue du Cimetière', '99999', 'Paradisville', 'fr', 's', 'm', '', NULL),
    (12, 1, 'Alize', 'Jeanne', '', '', '', 'Résidence ', '50 D rue Dr Soin', '01234', 'La Grand Ville', 'fr', 'b', 'f', '', NULL),
    (13, 1, 'Afeux', 'Pierre', 'pierrot@orange.fr', '', '', '', '', '', '', 'fr', 's', 'm', '', NULL),
    (14, 1, 'Hô', 'Marthe', '', '', NULL, '', '', '', '', 'fr', 'b', 'f', '', NULL),
    (15, 1, 'Pion', 'Tartan', 'tartanpion@orange.fr', '', NULL, '', '', '', '', 'fr', 's', 'm', 'Un quidam parmi les autres', NULL),
    (16, 1, 'Darme', 'Jean', 'marechaussee', '', NULL, '1 rue de la Prison', '', '75000', 'Paris', 'fr', 'b', 'm', 'Attention!', NULL),
    (17, 1, 'Grange', 'Jean', 'webmaster@essai.eu', '', NULL, '', '', '', '', 'fr', 's', 'm', '', NULL),
    (21, 1, 'Manvussat', 'Gérard', 'gerard.manvussat@essai.fr', '', NULL, 'Résidence "Nulle"', '14 Place Nette', '00000', 'Triffouilly les Oies', 'fr', 'b', 'm', '', NULL),
    (22, 1, 'Durand', 'J. Philippe', '', '', '', 'Rue des Faucilles', '', '', '', 'fr', 's', 'm', '', NULL),
    (23, 1, 'Lauchon', 'Paul', 'polochon@plume.fr', '0123456789', NULL, 'Rue des Pies', '', '01123', 'Jasseron', 'fr', 'b', 'm', '', NULL),
    (24, 1, 'Nissence', 'Rémi', 'reminissence@toto.fr', '09 87 65 43 21', NULL, '14 rue du Souvenir', '', '54321', 'Aire sur l\'Adour', 'fr', 'b', 'm', '', NULL),
    (25, 1, 'Naissance', 'Eva', 'evanaissance@tonmail.com', '', NULL, '9 rue de la Maternité', '', '74000', 'Annecy', 'fr', 'b', 'f', '', NULL),
    (26, 1, 'Oïde', 'Solène', 'solenoide@elec.com', '0123456789', NULL, 'Rue des Physiciens', '', '75000', 'Paris', 'fr', 's', 'f', '', NULL),
    (28, 1, 'Bine', 'Bob', 'bobine@defil.fr', '', NULL, '9 rue Jame Lacouture', '', '69000', 'Lyon', 'fr', 'b', 'm', '', NULL),
    (29, 1, 'Emic', 'Paul', 'polemique@polemique.com', '', '', 'Le Bourg', '', '03400', 'Gennetines', 'fr', 'b', 'm', '', NULL);
     
    --
    -- Index pour les tables exportées
    --
     
    --
    -- Index pour la table `dat_individus`
    --
    ALTER TABLE `dat_individus`
      ADD PRIMARY KEY (`id`),
      ADD UNIQUE KEY `nom_complet` (`nom`,`prenom`),
      ADD KEY `id_abo` (`id_abo`);
     
    --
    -- AUTO_INCREMENT pour les tables exportées
    --
     
    --
    -- AUTO_INCREMENT pour la table `dat_individus`
    --
    ALTER TABLE `dat_individus`
      MODIFY `id` int(10) UNSIGNED NOT NULL AUTO_INCREMENT, AUTO_INCREMENT=30;
    --
    -- Contraintes pour les tables exportées
    --
     
    --
    -- Contraintes pour la table `dat_individus`
    --
    ALTER TABLE `dat_individus`
      ADD CONSTRAINT `dat_individus_ibfk_1` FOREIGN KEY (`id_abo`) REFERENCES `dat_abonnes` (`id`) ON DELETE CASCADE ON UPDATE CASCADE;
     
    /*!40101 SET CHARACTER_SET_CLIENT=@OLD_CHARACTER_SET_CLIENT */;
    /*!40101 SET CHARACTER_SET_RESULTS=@OLD_CHARACTER_SET_RESULTS */;
    /*!40101 SET COLLATION_CONNECTION=@OLD_COLLATION_CONNECTION */;
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
    43
    44
    45
    46
    47
    48
    49
    50
    51
    52
    53
    54
    55
    56
    57
    58
    59
    60
    61
    62
    63
    64
    65
    66
    67
    68
    69
    70
    71
    72
    73
    74
    75
    76
    77
    78
    79
    80
    81
    82
    -- phpMyAdmin SQL Dump
    -- version 4.5.5.1
    -- <a href="http://www.phpmyadmin.net" target="_blank">http://www.phpmyadmin.net</a>
    --
    -- Client :  127.0.0.1
    -- Généré le :  Sam 05 Novembre 2016 à 17:54
    -- Version du serveur :  5.7.11
    -- Version de PHP :  7.0.4
     
    SET SQL_MODE = "NO_AUTO_VALUE_ON_ZERO";
    SET time_zone = "+00:00";
     
     
    /*!40101 SET @OLD_CHARACTER_SET_CLIENT=@@CHARACTER_SET_CLIENT */;
    /*!40101 SET @OLD_CHARACTER_SET_RESULTS=@@CHARACTER_SET_RESULTS */;
    /*!40101 SET @OLD_COLLATION_CONNECTION=@@COLLATION_CONNECTION */;
    /*!40101 SET NAMES utf8mb4 */;
     
    --
    -- Base de données :  `sirap`
    --
     
    -- --------------------------------------------------------
     
    --
    -- Structure de la table `dat_liens_act`
    --
     
    CREATE TABLE `dat_liens_act` (
      `id` int(10) UNSIGNED NOT NULL,
      `id_ind` int(10) UNSIGNED NOT NULL,
      `id_act` int(10) UNSIGNED NOT NULL
    ) ENGINE=InnoDB DEFAULT CHARSET=utf8 COLLATE=utf8_unicode_ci;
     
    --
    -- Contenu de la table `dat_liens_act`
    --
     
    INSERT INTO `dat_liens_act` (`id`, `id_ind`, `id_act`) VALUES
    (2, 6, 2),
    (9, 7, 4),
    (5, 12, 4),
    (10, 13, 4),
    (1, 13, 5),
    (3, 16, 3),
    (8, 21, 3);
     
    --
    -- Index pour les tables exportées
    --
     
    --
    -- Index pour la table `dat_liens_act`
    --
    ALTER TABLE `dat_liens_act`
      ADD PRIMARY KEY (`id`),
      ADD UNIQUE KEY `couple` (`id_ind`,`id_act`),
      ADD KEY `id_act` (`id_act`);
     
    --
    -- AUTO_INCREMENT pour les tables exportées
    --
     
    --
    -- AUTO_INCREMENT pour la table `dat_liens_act`
    --
    ALTER TABLE `dat_liens_act`
      MODIFY `id` int(10) UNSIGNED NOT NULL AUTO_INCREMENT, AUTO_INCREMENT=11;
    --
    -- Contraintes pour les tables exportées
    --
     
    --
    -- Contraintes pour la table `dat_liens_act`
    --
    ALTER TABLE `dat_liens_act`
      ADD CONSTRAINT `dat_liens_act_ibfk_1` FOREIGN KEY (`id_ind`) REFERENCES `dat_individus` (`id`) ON DELETE CASCADE ON UPDATE CASCADE,
      ADD CONSTRAINT `dat_liens_act_ibfk_2` FOREIGN KEY (`id_act`) REFERENCES `lst_activites` (`id`) ON DELETE CASCADE ON UPDATE CASCADE;
     
    /*!40101 SET CHARACTER_SET_CLIENT=@OLD_CHARACTER_SET_CLIENT */;
    /*!40101 SET CHARACTER_SET_RESULTS=@OLD_CHARACTER_SET_RESULTS */;
    /*!40101 SET COLLATION_CONNECTION=@OLD_COLLATION_CONNECTION */;

  9. #9
    Expert éminent sénior Avatar de Artemus24
    Homme Profil pro
    Agent secret au service du président Ulysses S. Grant !
    Inscrit en
    Février 2011
    Messages
    6 381
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Paris (Île de France)

    Informations professionnelles :
    Activité : Agent secret au service du président Ulysses S. Grant !
    Secteur : Finance

    Informations forums :
    Inscription : Février 2011
    Messages : 6 381
    Points : 19 064
    Points
    19 064
    Par défaut
    Salut smccbbm.

    1) Pour la table "dat_individus", il n'est pas nécessaire d'y mettre les numéros de téléphones car à l'avance, vous ne savez pas combien de numéros de téléphone possède un individu.
    Le mieux est de les externaliser en créant un table "telephone" ayant la structure suivante :
    --> 'id' : la même valeur qui vous avez attribuer pour la table "dat_individus". Ce n'est pas une clef primaire mais un index non unique.
    Cette colonne est aussi une clef étrangère qui va pointer sur la table "dat_individus".

    --> 'phone' : le numéro de téléphone.
    Vous pouvez en mettre de 0 à N pour une personne donnée.

    --> 'type' : c'est la désignation du numéro de téléphone, genre : "docmicile", "bureau", "mobile" ...

    Même remarque concernant les adresses. Vous devez aussi les externaliser :
    --> 'id' : la même valeur qui vous avez attribuer pour la table "dat_individus". Ce n'est pas une clef primaire mais un index non unique.
    Cette colonne est aussi une clef étrangère qui va pointer sur la table "dat_individus".

    --> 'adresse'.
    --> 'code_postal'
    --> 'ville'
    --> 'pays'

    --> 'type' : c'est le type d'adresse : "Fiscal", "domicile", "poste restante" ...

    Re-même remarque concernant le commentaire. Pourquoi ?
    Ce n'est pas une information pertinente à mettre dans une table dont vous allez acceder tout le temps.

    --> 'id' : la même valeur qui vous avez attribuer pour la table "dat_individus".
    C'est une clef primaire car vous aurez soit pas de commentaire, ou bien 1 et 1 seul commentaire, même s'il est très long.
    Cette colonne est aussi une clef étrangère qui va pointer sur la table "dat_individus".

    --> 'commentaire'.

    Remarque concernant vos déclaratives :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    `statut` varchar(1) DEFAULT NULL,
    Si la taille de votre chaîne de caractères est de longueur 1, elle ne sera donc pas variable.
    Autant mettre "char(01)" !

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    `cp` varchar(5) DEFAULT NULL,
    Le code postal est de longueur fixe,donc pourquoi mettre "varchar(5)". Autant mettre "char(05)".
    D'autre en consultant les codes postaux, je constate que la "Corse-du-Sud" est "2A" et la "Haute-Corse" est "2B", le code postal s'écrit en numérique.
    Exemple : "Ajaccio : 20000", "Bastia : "20200".
    En cas de doute, autant mettre "char(05)", plutôt que "integer unsigned".

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    `pays` enum('de','fr','uk') NOT NULL DEFAULT 'fr',
    Si vous avez besoin d'une liste de pays, autant créer une table des pays.
    Et bien sûr, vous créez une clef étrangère qui va pointer sur cette nouvelle table.
    Car si vous avez un nouveau pays, vous êtes obligé de modifier cette colonne, ce qui n'est pas bien.

    Pour les "varchar", autant mettre le maximum autorisé, c'est-à-dire "255", si vous vous limitez à un octet pour la longueur.

    Il y a un truc que je ne comprends pas bien avec la colonne "id_abo". Elle est toujours à "1". Pourquoi ?
    Et que représente nominalement cette colonne. Est-ce un numéro d'abonnement ? Un abonnement à quoi ?
    D'autre part, pourquoi mettre cette colonne dans la table "dat_individus" alors qu'elle est déjà présente dans la table "lst_activites" ?
    Je pense qu'elle n'a pas sa place dans la table "dat_individus".

    2) Pour la table "lst_activites", il y a deux problèmes.
    La colonne "id" ne vous sert à rien, car vous définissez le couple (id_abo ; designation) comme unique.
    Autant mettre ce couple en tant que clef primaire.

    Ensuite, la colonne "désignation" me pose un problème" de compréhension.
    Externaliser vos "designations" dans une table afin d'associer un identifiant à votre chaîne de caractères.
    Déjà, vous n'aurez pas de problèmes d'orthographe dans les noms.
    Et il est plus facile de manipuler des identifiant numérique, que de longue et interminable chaîne de caractères.
    Ensuite vous gagnerez un peu de place en évitant la répétition d'un libelle trop long.

    Comme cette table est une table association, vous devez mettre des clef étrangère qui vont pointer respectivement sur les tables mères.

    3) Pour la table "dat_liens_act", c'est une table associative.
    Pourquoi avez-vous une colonne "id" en tant que clef primaire, alors que vous créez un "index unique" sur le couple (id_ind ; id_act) ?
    Autant mettre votre couple comme clef primaire et supprimer la colonne "id" qui ne vous sert à rien.

    L'index "id_act" ne vous sert à rien puisque vous définissez séparemment chacune de vos colonnes comme des clefs étrangères.

    Dans une base de données, lorsque vous faites le dictionnaire de données, débrouillez-vous pour qu'une même colonne porte toujours le même nom.
    Je ne suis pas trop partisan de faire des distinctions en suffixant telle colonne pour dire que c'est une foreign key ou une primary key.
    Le nom et les déclaratives suffisent largement à comprendre le rôle qu'ils jouent dans la table, et de surcroit dans la base de données.
    Et faites en sorte qu'un nom désigne une et une seule chose et soit donc unique dans le sens que vous lui attribuer.

    @+
    Si vous êtes de mon aide, vous pouvez cliquer sur .
    Mon site : http://www.jcz.fr

  10. #10
    Membre éclairé
    Homme Profil pro
    Ingénieur en électrotechnique retraité
    Inscrit en
    Décembre 2008
    Messages
    1 579
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 72
    Localisation : France, Bas Rhin (Alsace)

    Informations professionnelles :
    Activité : Ingénieur en électrotechnique retraité

    Informations forums :
    Inscription : Décembre 2008
    Messages : 1 579
    Points : 804
    Points
    804
    Par défaut
    Bonjour Artemus24,

    En conclusion, au moins provisoire.
    Pour ma question initiale, je contrôle mes doublons avant de tenter de modifier ma table lst_activites avec un contrôle de la transaction et un éventuel rollback. Je ne suis pas très satisfait de ce contrôle car il ne contrôle que des valeurs exactes.
    Il n'est pas possible de tout mettre ici. Les tables que je vous ai transmises ne sont qu'un extrait d'une application plus large de gestion de bénévoles. J'envisage d'appliquer l'ensemble de vos conseils sur l'ensemble du projet.

    Concernant vos remarques ci-après, elle me paraissent à quelques détails près judicieuses. Je les commente donc.

    Citation Envoyé par Artemus24 Voir le message
    1) Pour la table "dat_individus", il n'est pas nécessaire d'y mettre les numéros de téléphones car à l'avance, vous ne savez pas combien de numéros de téléphone possède un individu.
    Le mieux est de les externaliser en créant un table "telephone" ayant la structure suivante :
    --> 'id' : la même valeur qui vous avez attribuer pour la table "dat_individus". Ce n'est pas une clef primaire mais un index non unique.
    Cette colonne est aussi une clef étrangère qui va pointer sur la table "dat_individus".

    --> 'phone' : le numéro de téléphone.
    Vous pouvez en mettre de 0 à N pour une personne donnée.

    --> 'type' : c'est la désignation du numéro de téléphone, genre : "domicile", "bureau", "mobile" ...
    Je suis d'accord.

    Citation Envoyé par Artemus24 Voir le message
    Même remarque concernant les adresses. Vous devez aussi les externaliser :
    --> 'id' : la même valeur que vous avez attribuer pour la table "dat_individus". Ce n'est pas une clef primaire mais un index non unique.
    Cette colonne est aussi une clef étrangère qui va pointer sur la table "dat_individus".

    --> 'adresse'.
    --> 'code_postal'
    --> 'ville'
    --> 'pays'

    --> 'type' : c'est le type d'adresse : "Fiscal", "domicile", "poste restante" ...
    Je suis d'accord, mais je ne suis pas sûr d'avoir besoin du type. Je verrai, si j'en ai besoin ultérieurement.

    Citation Envoyé par Artemus24 Voir le message
    Re-même remarque concernant le commentaire. Pourquoi ?
    Ce n'est pas une information pertinente à mettre dans une table dont vous allez acceder tout le temps.

    --> 'id' : la même valeur qui vous avez attribuer pour la table "dat_individus".
    C'est une clef primaire car vous aurez soit pas de commentaire, ou bien 1 et 1 seul commentaire, même s'il est très long.
    Cette colonne est aussi une clef étrangère qui va pointer sur la table "dat_individus".

    --> 'commentaire'.
    C'est le point qui me paraît le plus important.

    Citation Envoyé par Artemus24 Voir le message
    Remarque concernant vos déclaratives :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    `statut` varchar(1) DEFAULT NULL,
    Si la taille de votre chaîne de caractères est de longueur 1, elle ne sera donc pas variable.
    Autant mettre "char(01)" !
    Et pourquoi pas "char(1)"?

    Citation Envoyé par Artemus24 Voir le message
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    `cp` varchar(5) DEFAULT NULL,
    Le code postal est de longueur fixe,donc pourquoi mettre "varchar(5)". Autant mettre "char(05)".
    D'autre en consultant les codes postaux, je constate que la "Corse-du-Sud" est "2A" et la "Haute-Corse" est "2B", le code postal s'écrit en numérique.
    Exemple : "Ajaccio : 20000", "Bastia : "20200".
    En cas de doute, autant mettre "char(05)", plutôt que "integer unsigned".
    Attention, la taille n'est pas la même à l'étranger, je crois même qu'elle est variable au Royaume uni et dans d'autres pays. A vérifier.

    Citation Envoyé par Artemus24 Voir le message
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    `pays` enum('de','fr','uk') NOT NULL DEFAULT 'fr',
    Si vous avez besoin d'une liste de pays, autant créer une table des pays.
    Et bien sûr, vous créez une clef étrangère qui va pointer sur cette nouvelle table.
    Car si vous avez un nouveau pays, vous êtes obligé de modifier cette colonne, ce qui n'est pas bien.
    J'ai déjà une liste de pays exhaustive (à ce jour) et cette colonne est destinée à être remplacée par l'id (code pays) de cette liste qui utilise la norme 3166 à 2 caractères. D'autant que enum n'est pas standard mais propre à MySQL.

    Citation Envoyé par Artemus24 Voir le message
    Pour les "varchar", autant mettre le maximum autorisé, c'est-à-dire "255", si vous vous limitez à un octet pour la longueur.
    Citation Envoyé par Artemus24 Voir le message
    Il y a un truc que je ne comprends pas bien avec la colonne "id_abo". Elle est toujours à "1". Pourquoi ?
    Parce qu'il s'agit d'un jeu d'essai, mais elle est destinée à être variable.

    Citation Envoyé par Artemus24 Voir le message
    Et que représente nominalement cette colonne. Est-ce un numéro d'abonnement ? Un abonnement à quoi ?
    D'autre part, pourquoi mettre cette colonne dans la table "dat_individus" alors qu'elle est déjà présente dans la table "lst_activites" ?
    Je pense qu'elle n'a pas sa place dans la table "dat_individus".
    S'agissant d'un élément de sécurité important, je l'ai mis volontairement à plusieurs endroits (donc redondants) pour le contrôler à chaque requête.

    Citation Envoyé par Artemus24 Voir le message
    2) Pour la table "lst_activites", il y a deux problèmes.
    La colonne "id" ne vous sert à rien, car vous définissez le couple (id_abo ; designation) comme unique.
    Autant mettre ce couple en tant que clef primaire.
    J'y avais pensé mais je n'étais pas sûr de moi. Je vais l'enlever.

    Citation Envoyé par Artemus24 Voir le message
    Ensuite, la colonne "désignation" me pose un problème" de compréhension.
    Externaliser vos "designations" dans une table afin d'associer un identifiant à votre chaîne de caractères.
    Déjà, vous n'aurez pas de problèmes d'orthographe dans les noms.
    Et il est plus facile de manipuler des identifiant numérique, que de longue et interminable chaîne de caractères.
    Ensuite vous gagnerez un peu de place en évitant la répétition d'un libelle trop long.
    C'est justement cette table qui est la table externe qui permet de faire le lien avec la table dat_individus via la table associative dat_liens_act

    Citation Envoyé par Artemus24 Voir le message
    Comme cette table est une table association, vous devez mettre des clef étrangère qui vont pointer respectivement sur les tables mères.
    Mais non, c'est la table dat_liens_act qui associe la table dat_individus à la table lst_activites via des clefs étrangères (id_ind et id_act). Ou alors, je ne comprends pas ce que vous voulez dire.

    Citation Envoyé par Artemus24 Voir le message
    3) Pour la table "dat_liens_act", c'est une table associative.
    Pourquoi avez-vous une colonne "id" en tant que clef primaire, alors que vous créez un "index unique" sur le couple (id_ind ; id_act) ?
    Autant mettre votre couple comme clef primaire et supprimer la colonne "id" qui ne vous sert à rien.
    C'est vrai.

    Citation Envoyé par Artemus24 Voir le message
    L'index "id_act" ne vous sert à rien puisque vous définissez séparément chacune de vos colonnes comme des clefs étrangères.
    OK

    Citation Envoyé par Artemus24 Voir le message
    Dans une base de données, lorsque vous faites le dictionnaire de données, débrouillez-vous pour qu'une même colonne porte toujours le même nom.
    Je ne suis pas trop partisan de faire des distinctions en suffixant telle colonne pour dire que c'est une foreign key ou une primary key.
    Le nom et les déclaratives suffisent largement à comprendre le rôle qu'ils jouent dans la table, et de surcroit dans la base de données.
    Et faites en sorte qu'un nom désigne une et une seule chose et soit donc unique dans le sens que vous lui attribuer.
    Merci pour tous ces conseils!

  11. #11
    Modérateur
    Avatar de escartefigue
    Homme Profil pro
    bourreau
    Inscrit en
    Mars 2010
    Messages
    10 136
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Loir et Cher (Centre)

    Informations professionnelles :
    Activité : bourreau
    Secteur : Finance

    Informations forums :
    Inscription : Mars 2010
    Messages : 10 136
    Points : 38 561
    Points
    38 561
    Billets dans le blog
    9
    Par défaut
    Citation Envoyé par smccbbm Voir le message
    Citation Envoyé par Artemus24 Voir le message
    2) est-il pertinent de créer un index unique sur le couple (`id_abo`,`designation`)


    Oui, puisque c'est ce couple qui doit être unique.

    Non car ceci est symptomatique d'une modélisation mal faite : id_abo et désignation devraient être des attributs d'une table "abonnés" par exemple, dans laquelle l'id_abo étant unique, la désignation est forcément unique


    Citation Envoyé par smccbbm Voir le message
    Il s'agit de définition courtes et peu nombreuses pour un même abonné (id_abo). Ce n'est pas absolu, car on est pas à l'abri de modifications légères d'un libellé, mais je ne vois pas d'autres solutions.

    .
    Une chaine de caractères ne devrait pas etre retenue comme clef primaire pour de nombreuses raisons, en voici les principales :
    - le plus souvent le char ou varchar (ou text ou nchar ou nvarchar) contient des valeurs sémantiques, donc potentiellement instables, or une clef primaire doit avant tout être stable
    - le char (ou varchar etc...) est coûteux en taille comparativement à de l'integer (ou small ou big), or une clef surtout primaire, doit être concise
    - le char (ou varchar etc...) est sensible à la collation, ce qui nécessite des calculs supplémentaires dans la base de données et rend les résultats potentiellement différents si vous transportez les données dans une autre base/table/colonne (dont la collation serait différente)

    Il ne faut pas perdre à l'esprit que les identifiants primaires sont
    - ceux utilisés le plus souvent pour les jointures, c'est la raison pour laquelle ils doivent être concis : moins on transporte de données mieux ca vaut pour le réseau, l'espace disque et les perfs
    - ceux utilisés pour garantir l'intégrité de la base de donnée, via les contraintes, c'est la raison pour laquelle ils doivent être stables. Les valeurs sémantiques sont à proscrire, car si une clef change, c'est une cascade de mises à jour qui se déclenche, ce qui peut mettre à plat une BDD volumineuse.

  12. #12
    Expert éminent sénior Avatar de Artemus24
    Homme Profil pro
    Agent secret au service du président Ulysses S. Grant !
    Inscrit en
    Février 2011
    Messages
    6 381
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Paris (Île de France)

    Informations professionnelles :
    Activité : Agent secret au service du président Ulysses S. Grant !
    Secteur : Finance

    Informations forums :
    Inscription : Février 2011
    Messages : 6 381
    Points : 19 064
    Points
    19 064
    Par défaut
    Salut à tous.

    Citation Envoyé par smccbbm
    Et pourquoi pas "char(1)"?
    Pourquoi une question ? C'est ce que je vous conseille de mettre au lieu de "varchar(01)".

    Citation Envoyé par smccbbm
    Attention, la taille n'est pas la même à l'étranger, je crois même qu'elle est variable au Royaume uni et dans d'autres pays. A vérifier.
    Le format du code postal que je vous conseille ("char(05)"), c'est pour la France.
    Ailleurs, je ne saurai pas répondre s'il existe un code postal et si celui-ci est de longueur fixe ou pas.
    Dans ce cas, il faudra plutôt envisager une saisie des adresses d'une manière plus souple.

    Citation Envoyé par smccbbm
    D'autant que enum n'est pas standard mais propre à MySQL.
    La question ne se porte pas sur si c'est standard ou pas, mais sur l'évolution de cette colonne.
    Au lieu d'avoir un ensemble fixe et donc non modifiable de valeur pour cette colonne, il faut mieux jouer la souplesse.
    A savoir, une table des codes pays, et pour la colonne, la transformer en clef étrangère sur cette table.
    Après, si vous utilisez un code numérique ou alphabétique, on s'en fout.

    Citation Envoyé par smccbbm
    S'agissant d'un élément de sécurité important, je l'ai mis volontairement à plusieurs endroits (donc redondants) pour le contrôler à chaque requête.
    Vous n'avez pas répondu à la question !

    J'ai compris que cet identifiant (numéro d'abonné), qui est donc une clef étrangère, pointe vers la table des abonnés.
    Mais que représente ce numéro d'abonné ? Y-a-t-il un abonné par client, ou peut-il en avoir plusieurs ?
    Comment vient-il s'insérer fonctionnellement dans votre base de données ?

    Citation Envoyé par smccbbm
    C'est justement cette table qui est la table externe qui permet de faire le lien avec la table dat_individus via la table associative dat_liens_act
    C'est cette table "lst_activites" que je ne comprends pas trop l'utilité.

    En ce qui concerne les "désignations", je suppose que ce sont des libellés fixés dont vous allez associer à des clients
    Donc créez une table destiné qu'à cet usage :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    1, "Accueil de jour"
    2, "Accueil de nuit"
    3, "Conseil d'administration"
    4, "Manutention"
    5, "Vente braderie"
    6, "Vente magasin"
    ...
    et n'introduisez pas le numéro d'abonné dedans.
    Il y aura deux colonnes, dont l'une est "designation_id" et l'autre "designation_lib".

    Citation Envoyé par smccbbm
    Mais non, c'est la table dat_liens_act qui associe la table dat_individus à la table lst_activites via des clefs étrangères (id_ind et id_act). Ou alors, je ne comprends pas ce que vous voulez dire.
    Je ne parle pas de la table "dat_liens_act" mais bien de la table "lst_activites" qui n'est pas très clair dans l'usage que vous en faites.
    Je pense que la table "lst-activites" est mal définie dans votre base de données.
    Le mieux est de la fusionner avec la table association "dat_lien_act", comme ci-après :
    --> 'id_ind' qui va pointer sur la colonne 'id' de la table "dat_individus".
    --> 'id_act' qu'il faut rebaptiser en 'designation_id' et qui va pointer sur la table "désignations".
    ces deux colonnes formes soit la clef primaire, soit un index unique selon l'usage que vous allez faire de cette table.
    Si vous faites références à cette table, en tant que clef étrangère, il faudra créer une colonne 'id' auto_incrémentée.

    --> 'id_abo' qui va pointer sur la colonne 'id' de la table 'dat_abonnes'.
    A priori, c'est une information et non une clef.

    C'est le rôle joué par la colonne "id_abo", ainsi que la colonne "désignation" qui ne sont pas très clair.

    Citation Envoyé par Escartefigue
    Non car ceci est symptomatique d'une modélisation mal faite : id_abo et désignation devraient être des attributs d'une table "abonnés" par exemple, dans laquelle l'id_abo étant unique, la désignation est forcément unique
    Selon moi, ce couple montre une mauvaise compréhension du rôle joué dans la base des données.
    D'où votre remarque sur un problème de modélisation.

    Citation Envoyé par Escartefigue
    Une chaine de caractères ne devrait pas etre retenue comme clef primaire
    Sur le principe, je suis d'accord !
    Dans l'usage de la colonne "désignation" que fait "smccbbm", c'est même une erreur de conception.
    Puisque cette chaîne de caractères est un libellé et non un code de type alphanumérique.

    @+
    Si vous êtes de mon aide, vous pouvez cliquer sur .
    Mon site : http://www.jcz.fr

Discussions similaires

  1. [Flex4] empêcher les doublons dropés
    Par supertonic dans le forum Flex
    Réponses: 4
    Dernier message: 01/09/2010, 20h29
  2. Empêcher les doublons dans une table
    Par Niki59 dans le forum Langage
    Réponses: 2
    Dernier message: 16/11/2008, 11h33
  3. Empêcher les doublons dans le résultat de la requête
    Par bouba_95 dans le forum Requêtes et SQL.
    Réponses: 4
    Dernier message: 17/07/2007, 18h32
  4. Empêcher les doublons
    Par sam01 dans le forum Requêtes
    Réponses: 3
    Dernier message: 19/12/2006, 21h32
  5. Empécher les doublon avec les post
    Par Death83 dans le forum Langage
    Réponses: 15
    Dernier message: 20/07/2006, 09h22

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