Mysql
 sql >> Base de données >  >> RDS >> Mysql

SQL :Création d'une table de relations avec 2 auto_increment différents

Concepts

Vous avez mal compris certains concepts de base, et les difficultés en découlent. Nous devons d'abord aborder les concepts, pas le problème tel que vous le percevez, et par conséquent, votre problème disparaîtra.

ID incrémentés automatiquement, qui sont bien sûr des clés primaires.

Non ils ne sont pas. C'est une idée fausse courante. Et les problèmes sont garantis.

Un ID le champ ne peut pas être une clé primaire au sens anglais ou technique ou relationnel.

  • Bien sûr, en SQL, vous pouvez déclarer tout le champ doit être une PRIMARY KEY , mais cela ne la transforme pas comme par magie en clé primaire au sens anglais, technique ou relationnel. Vous pouvez nommer un chihuahua "Rottweiller", mais cela ne le transforme pas en Rottweiller, il reste un chihuahua. Comme tout langage, SQL exécute simplement les commandes que vous lui donnez, il ne comprend pas la PRIMARY KEY pour signifier quelque chose de relationnel, cela frappe simplement un index unique sur la colonne (ou le champ).

  • Le problème est que puisque vous avez déclaré l'ID être une PRIMARY KEY , vous pensez en tant que clé primaire, et vous pouvez attendre qu'il a certaines des qualités d'une clé primaire. À l'exception de l'unicité de l'ID valeur , il n'offre aucun avantage. Il n'a aucune des qualités d'une clé primaire, ni aucune sorte de clé relationnelle d'ailleurs. Ce n'est pas une clé au sens anglais, technique ou relationnel. En déclarant qu'une non-clé est une clé, vous ne ferez que vous confondre et vous découvrirez qu'il y a quelque chose de terriblement faux uniquement lorsque l'utilisateur se plaint de doublons dans la table.

Les tables relationnelles doivent avoir une ligne unicité

Une PRIMARY KEY sur un ID le champ ne fournit pas de ligne unicité. Ce n'est donc pas une table relationnelle contenant des lignes, et si ce n'est pas cela, alors c'est un fichier contenant des enregistrements. Il n'a ni l'intégrité, ni la puissance (à ce stade, vous ne serez conscient que de la puissance de jointure) ni la vitesse d'une table dans une base de données relationnelle.

Exécutez ce code (MS SQL 2008) et prouvez-le vous-même. Veuillez ne pas simplement lire ceci et le comprendre, puis continuer à lire le reste de cette réponse, ce code doit être exécuté avant de continuer . Il a une valeur curative.

    CREATE TABLE dumb_file (
        id         INT      NOT NULL  IDENTITY  PRIMARY KEY,
        name_first CHAR(30) NOT NULL,
        name_last  CHAR(30) NOT NULL
        )

    INSERT dumb_file VALUES ( "Mickey", "Mouse" )  -- succeeds
    INSERT dumb_file VALUES ( "Mickey", "Mouse" )  -- succeeds, but not intended
    INSERT dumb_file VALUES ( "Mickey", "Mouse" )  -- succeeds, but not intended

    SELECT * FROM dumb_file

Notez que vous avez des lignes en double . Les tables relationnelles doivent avoir des lignes uniques . Une preuve supplémentaire que vous n'avez pas de table relationnelle, ou aucune des qualités d'une table.

Notez que dans votre rapport, la seule chose qui est unique est l'ID champ, dont aucun utilisateur ne se soucie, aucun utilisateur ne voit, car ce ne sont pas des données, c'est un non-sens supplémentaire qu'un "professeur" très stupide vous a dit de mettre dans chaque fichier. Vous avez enregistrement unicité mais pas ligne unicité.

En termes de données (les données réelles moins les ajouts superflus), les données name_last et name_first peut exister sans l'ID domaine. Une personne a un prénom et un nom de famille sans qu'une pièce d'identité ne soit estampée sur son front.

La deuxième chose que vous utilisez qui vous déroute est le AUTOINCREMENT. Si vous implémentez un système de classement d'enregistrements sans capacité relationnelle, bien sûr, c'est utile, vous n'avez pas à coder l'incrément lors de l'insertion d'enregistrements. Mais si vous implémentez une base de données relationnelle, cela ne sert à rien, car vous ne l'utiliserez jamais. Il existe de nombreuses fonctionnalités dans SQL que la plupart des gens n'utilisent jamais.

Mesure corrective

Alors, comment mettre à niveau, élever, ce dumb_file plein de lignes en double vers une table relationnelle, afin d'obtenir certaines des qualités et des avantages d'une table relationnelle ? Il y a trois étapes pour cela.

  1. Vous devez comprendre les clés

    • Et depuis que nous sommes passés des fichiers ISAM des années 1970 au modèle relationnel , vous devez comprendre les clés relationnelles . C'est-à-dire si vous souhaitez bénéficier des avantages (intégrité, puissance, rapidité) d'une base de données relationnelle.

    Dr E F Cood, dans son MR , a déclaré que :

    une clé est constituée à partir des données

    et

    les lignes d'un tableau doivent être uniques

    Votre "clé" n'est pas constituée à partir des données. Il s'agit d'un parasite supplémentaire, non lié aux données, causé par votre infection par la maladie de votre "professeur". Reconnaissez-le comme tel et accordez-vous la pleine capacité mentale que Dieu vous a donnée (notez que je ne vous demande pas de penser en termes isolés ou fragmentés ou abstraits, tous les éléments d'une base de données doivent être intégrés les uns aux autres). Construire une vraie clé à partir des données, et uniquement à partir des données. Dans ce cas, il n'y a qu'une seule clé possible :(name_last, name_first).

  2. Essayez ce code , déclarer une contrainte unique sur les données :

         CREATE TABLE dumb_table (
            id         INT      NOT NULL  IDENTITY  PRIMARY KEY,
            name_first CHAR(30) NOT NULL,
            name_last  CHAR(30) NOT NULL
    
            CONSTRAINT UK 
                UNIQUE ( name_last, name_first )
            )
    
        INSERT dumb_table VALUES ( "Mickey", "Mouse" )  -- succeeds
        INSERT dumb_table VALUES ( "Mickey", "Mouse" )  -- fails, as intended
        INSERT dumb_table VALUES ( "Minnie", "Mouse" )  -- succeeds
    
        SELECT * FROM dumb_table
    

    Nous avons maintenant unicité de ligne . C'est la séquence qui arrive à la plupart des gens :ils créent un fichier qui autorise les dupes; ils n'ont aucune idée de la raison pour laquelle les dupes apparaissent dans les listes déroulantes ; l'utilisateur crie ; ils modifient le fichier et ajoutent un index pour éviter les doublons ; ils passent au correctif de bogue suivant. (Ils peuvent le faire correctement ou non, c'est une autre histoire.)

  3. Le deuxième niveau. Pour les personnes réfléchies qui pensent au-delà des solutions. Puisque nous avons maintenant l'unicité des lignes, quel est le but de l'ID champ, pourquoi l'avons-nous même ??? Oh, parce que le chihuahua s'appelle Rotty et qu'on a peur de le toucher.

    La déclaration qu'il s'agit d'une PRIMARY KEY est faux, mais il demeure, causant de la confusion et de fausses attentes. La seule véritable clé qui existe est le (name_last, name_fist), et c'est une clé alternative à ce stade.

    Donc l'ID le champ est totalement superflu ; et il en va de même pour l'index qui le supporte ; et le stupide AUTOINCREMENT aussi; ainsi que la fausse déclaration selon laquelle il s'agit d'une PRIMARY KEY; et toutes les attentes que vous pourriez en avoir sont fausses.

    Supprimez donc le superflu ID domaine. Essayez ce code :

        CREATE TABLE honest_table (
            name_first CHAR(30) NOT NULL,
            name_last  CHAR(30) NOT NULL
    
            CONSTRAINT PK 
            PRIMARY KEY ( name_last, name_first )
            )
    
        INSERT honest_table VALUES ( "Mickey", "Mouse" )  -- succeeds
        INSERT honest_table VALUES ( "Mickey", "Mouse" )  -- fails, as intended
        INSERT honest_table VALUES ( "Minnie", "Mouse" )  -- succeeds
    
        SELECT * FROM honest_table
    

    Fonctionne très bien, fonctionne comme prévu, sans les champs et index superflus.

    S'il vous plaît rappelez-vous ceci, et faites-le correctement, à chaque fois.

Faux enseignants

En ces derniers temps, comme conseillé, nous en aurons beaucoup. Notez bien, les "enseignants" qui propagent ID les colonnes, en vertu des preuves détaillées de cet article, ne comprennent tout simplement pas le modèle relationnel ou bases de données relationnelles. Surtout ceux qui écrivent des livres à ce sujet.

Comme on le voit, ils sont bloqués dans la technologie ISAM d'avant 1970. C'est tout ce qu'ils comprennent et c'est tout ce qu'ils peuvent enseigner. Ils utilisent un conteneur de base de données SQL, pour la facilité d'accès, de récupération, de sauvegarde, etc., mais le contenu est un pur système de classement d'enregistrements sans intégrité relationnelle, puissance ou vitesse. AFAIC, c'est une fraude grave.

En plus de ID domaines, bien sûr, il y a plusieurs éléments qui sont des concepts clés relationnels ou non, qui, pris ensemble, m'amènent à tirer une conclusion aussi grave. Ces autres éléments dépassent le cadre de cet article.

Une paire d'idiots en particulier monte actuellement un assaut sur First Normal Form. Ils appartiennent à l'asile.

Répondre

Maintenant pour le reste de votre question.

Existe-t-il un moyen de créer une table relationnelle sans perdre les fonctionnalités d'incrémentation automatique ?

C'est une phrase qui se contredit. J'espère que vous comprendrez d'après mon explication, les tables relationnelles n'ont pas besoin pour AUTOINCREMENT "fonctionnalités"; si le fichier a AUTOINCREMENT , ce n'est pas une table relationnelle.

AUTOINCREMENT n'est bon que pour une chose :si, et seulement si, vous souhaitez créer une feuille de calcul Excel dans le conteneur de la base de données SQL, remplie de champs nommés A, B, et C, en haut et enregistrez les numéros en bas à gauche. En termes de base de données, c'est le résultat d'un SELECT, une vue aplatie des données, qui n'est pas la source de données, qui est organisé (Normalisé).

Une autre solution possible (mais non préférée) peut être qu'il y a une autre clé primaire dans la première table, qui est le nom d'utilisateur de l'utilisateur, pas avec une instruction d'incrémentation automatique, bien sûr. Est-ce inévitable ?

Dans le travail technique, nous ne nous soucions pas des préférences, car c'est subjectif et cela change tout le temps. Nous nous soucions de l'exactitude technique, car c'est objectif et cela ne change pas.

Oui, c'est inévitable. Parce que ce n'est qu'une question de temps; nombre de bogues ; nombre de "ne peut pas faire" ; nombre de cris d'utilisateurs, jusqu'à ce que vous fassiez face aux faits, surmontiez vos fausses déclarations et réalisiez que :

  • le seul moyen de s'assurer que l'utilisateur lignes sont uniques, que les user_names sont uniques, est de déclarer un UNIQUE contrainte sur elle

  • et se débarrasser de user_id ou id dans la fiche utilisateur

  • qui promeut user_name à PRIMARY KEY

Oui, car tout votre problème avec la troisième table, pas par hasard, est alors éliminé.

Cette troisième table est une table associative . La seule clé requise (clé primaire) est un composé des deux clés primaires parentes. Cela garantit l'unicité des lignes , qui sont identifiés par leurs clés, et non par leurs IDs.

Je vous mets en garde à ce sujet parce que les mêmes "professeurs" qui vous ont appris l'erreur d'implémenter ID champs, enseignez l'erreur d'implémentation de ID champs de la table associative, où, tout comme avec une table ordinaire, il est superflu, ne sert à rien, introduit des doublons et prête à confusion. Et c'est doublement superflu car les deux clés qui fournissent sont déjà là, nous regardant en face.

Puisqu'ils ne comprennent pas le RM , ou termes relationnels, ils appellent les tables associatives des tables de "lien" ou de "carte". S'ils ont un ID champ, ce sont en fait des fichiers.

Tableaux de recherche

ID les champs sont particulièrement Chose stupide à faire pour les tables de recherche ou de référence. La plupart d'entre eux ont des codes reconnaissables, il n'est pas nécessaire d'énumérer la liste des codes qu'ils contiennent, car les codes sont (devraient être) uniques.

De plus, avoir les codes dans les tables enfants en tant que FK est une bonne chose :le code est beaucoup plus significatif et évite souvent une jointure inutile :

    SELECT ...
        FROM child_table           -- not the lookup table
        WHERE gender_code = "M"    -- FK in the child, PK in the lookup

au lieu de :

    SELECT ...
        FROM child_table
        WHERE gender_id = 6        -- meaningless to the maintainer

ou pire :

    SELECT ...
        FROM child_table C         -- that you are trying to determine
        JOIN lookup_table L
            ON C.gender_id = L.gender_id
        WHERE L.gender_code = "M"  -- meaningful, known

Notez que c'est quelque chose que l'on ne peut pas éviter :vous avez besoin d'unicité sur le code de recherche et unicité sur la description. C'est la seule méthode pour éviter les doublons dans chaque des deux colonnes :

    CREATE TABLE gender (
        gender_code  CHAR(2)  NOT NULL,
        name         CHAR(30) NOT NULL

        CONSTRAINT PK 
            PRIMARY KEY ( gender_code )

        CONSTRAINT AK 
            UNIQUE ( name )
        )

Exemple complet

D'après les détails de votre question, je soupçonne que vous avez des problèmes de syntaxe SQL et de définition FK, je vais donc donner la solution complète dont vous avez besoin à titre d'exemple (puisque vous n'avez pas donné de définitions de fichiers) :

    CREATE TABLE user (                 -- Typical Identifying Table
        user_name  CHAR(16) NOT NULL,   -- Short PK
        name_first CHAR(30) NOT NULL,   -- Alt Key.1
        name_last  CHAR(30) NOT NULL,   -- Alt Key.2
        birth_date DATE     NOT NULL    -- Alt Key.3

        CONSTRAINT PK                   -- unique user_name
            PRIMARY KEY ( user_name )

        CONSTRAINT AK                   -- unique person identification
            PRIMARY KEY ( name_last, name_first, birth_date )
        )

    CREATE TABLE sport (                  -- Typical Lookup Table
        sport_code  CHAR(4)  NOT NULL,    -- PK Short code
        name        CHAR(30) NOT NULL     -- AK

        CONSTRAINT PK 
            PRIMARY KEY ( sport_code )

        CONSTRAINT AK 
            PRIMARY KEY ( name )
        )

    CREATE TABLE user_sport (           -- Typical Associative Table
        user_name  CHAR(16) NOT NULL,   -- PK.1, FK
        sport_code CHAR(4)  NOT NULL,   -- PK.2, FK
        start_date DATE     NOT NULL

        CONSTRAINT PK 
            PRIMARY KEY ( user_name, sport_code )

        CONSTRAINT user_plays_sport_fk
            FOREIGN KEY     ( user_name )
            REFERENCES user ( user_name )

        CONSTRAINT sport_occupies_user_fk
            FOREIGN KEY      ( sport_code )
            REFERENCES sport ( sport_code )
        )

Là, la PRIMARY KEY déclaration est honnête, c'est une clé primaire ; pas d'ID; non AUTOINCREMENT; pas d'indices supplémentaires ; pas de lignes en double; pas d'attentes erronées ; aucun problème consécutif.

Modèle de données

Voici le modèle de données pour aller avec les définitions.

  • Exemple de modèle de données sportives utilisateur

  • Si vous n'êtes pas habitué à la notation, sachez que chaque petite coche, encoche et marque, les lignes pleines par rapport aux pointillés, les coins carrés par rapport aux coins ronds, signifient quelque chose de très spécifique. Reportez-vous à la Notation IDEF1X .

  • Une image vaut mieux que mille mots; dans ce cas, une image de plainte standard vaut plus que cela; un mauvais ne vaut pas le papier sur lequel il est dessiné.

  • Veuillez vérifier attentivement les phrases verbales, elles comprennent un ensemble de prédicats. Le reste des prédicats peut être déterminé directement à partir du modèle. Si ce n'est pas clair, veuillez demander.