Mysql
 sql >> Datenbank >  >> RDS >> Mysql

SQL:Erstellen einer Beziehungstabelle mit 2 verschiedenen auto_increment

Konzepte

Sie haben einige grundlegende Konzepte missverstanden, und daraus resultieren die Schwierigkeiten. Wir müssen uns zuerst mit den Konzepten befassen, nicht mit dem Problem, wie Sie es wahrnehmen, und folglich wird Ihr Problem verschwinden.

automatisch inkrementierte IDs, die natürlich Primärschlüssel sind.

Nein sind sie nicht. Das ist ein weit verbreiteter Irrglaube. Und Probleme sind garantiert.

Eine ID Feld kann kein Primärschlüssel im englischen oder technischen oder relationalen Sinne sein.

  • Sicher, in SQL können Sie any deklarieren Feld als PRIMARY KEY , aber das verwandelt es nicht auf magische Weise in einen Primärschlüssel im englischen, technischen oder relationalen Sinne. Man kann einen Chihuahua „Rottweiller“ nennen, aber das macht ihn nicht zu einem Rottweiller, er bleibt ein Chihuahua. Wie jede Sprache führt SQL einfach die Befehle aus, die Sie ihm geben, es versteht PRIMARY KEY nicht um etwas Relationales zu bedeuten, schlägt es einfach einen eindeutigen Index auf die Spalte (oder das Feld).

  • Das Problem ist, da Sie deklariert haben die ID ein PRIMARY KEY sein , denken Sie davon als Primärschlüssel, und Sie können erwarten dass es einige Qualitäten eines Primärschlüssels hat. Abgesehen von der Eindeutigkeit des ID-Werts , bringt es keinen Nutzen. Es hat keine der Qualitäten eines Primärschlüssels oder irgendeiner Art von relationalem Schlüssel für diese Angelegenheit. Es ist kein Schlüssel im englischen, technischen oder relationalen Sinne. Indem Sie einen Nicht-Schlüssel zu einem Schlüssel erklären, verwirren Sie sich nur selbst und finden erst heraus, dass etwas furchtbar falsch läuft, wenn sich der Benutzer über Duplikate in der Tabelle beschwert.

Relationale Tabellen müssen row haben Einzigartigkeit

Ein PRIMARY KEY auf einer ID Feld stellt keine Zeile bereit Einzigartigkeit. Daher ist es keine relationale Tabelle, die Zeilen enthält, und wenn dies nicht der Fall ist, dann ist es eine Datei, die Datensätze enthält. Sie hat nicht die Integrität oder Leistung (zu diesem Zeitpunkt werden Sie sich nur der Join-Leistung bewusst sein) oder Geschwindigkeit, die eine Tabelle in einer relationalen Datenbank hat.

Führen Sie diesen Code aus (MS SQL 2008) und überzeugen Sie sich selbst. Bitte lesen Sie dies nicht einfach und verstehen Sie es, und lesen Sie dann den Rest dieser Antwort, dieser Code muss ausgeführt werden, bevor Sie weiterlesen . Es hat heilenden Wert.

    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

Beachten Sie, dass Sie doppelte Zeilen haben . Relationale Tabellen müssen eindeutige Zeilen haben . Ein weiterer Beweis dafür, dass Sie keine relationale Tabelle oder irgendwelche Eigenschaften einer solchen haben.

Beachten Sie, dass in Ihrem Bericht nur die ID eindeutig ist Feld, um das sich kein Benutzer kümmert, das kein Benutzer sieht, weil es keine Daten sind, es ist ein zusätzlicher Unsinn, den Ihnen ein sehr dummer "Lehrer" gesagt hat, Sie sollen jede Datei einfügen. Sie haben Eintrag Eindeutigkeit, aber nicht row Einzigartigkeit.

In Bezug auf die Daten (die echten Daten abzüglich der fremden Zusätze), die Daten name_last und name_first kann ohne die ID existieren Feld. Eine Person hat einen Vornamen und einen Nachnamen, ohne dass ein Ausweis auf der Stirn eingeprägt ist.

Die zweite Sache, die Sie verwenden, die Sie verwirrt, ist AUTOINCREMENT. Wenn Sie ein Datensatzablagesystem ohne relationale Funktion implementieren, ist es sicherlich hilfreich, dass Sie beim Einfügen von Datensätzen das Inkrement nicht codieren müssen. Aber wenn Sie eine relationale Datenbank implementieren, hat sie überhaupt keinen Zweck, weil Sie sie nie verwenden werden. Es gibt viele Funktionen in SQL, die die meisten Leute nie verwenden.

Korrekturmaßnahme

Wie können Sie also diese dumb_file, die voller doppelter Zeilen ist, auf eine relationale Tabelle aktualisieren, erhöhen, um einige der Eigenschaften und Vorteile einer relationalen Tabelle zu erhalten? Dazu sind drei Schritte erforderlich.

  1. Sie müssen Keys verstehen

    • Und seit wir von den ISAM-Dateien der 1970er zum Relational Model übergegangen sind , müssen Sie relationale Schlüssel verstehen . Das heißt, wenn Sie die Vorteile (Integrität, Leistung, Geschwindigkeit) einer relationalen Datenbank nutzen möchten.

    Dr. E. F. Cood, in seinem RM , hat Folgendes erklärt:

    aus den Daten wird ein Schlüssel gebildet

    und

    Die Zeilen in einer Tabelle müssen eindeutig sein

    Ihr „Schlüssel“ besteht nicht aus den Daten. Es ist ein zusätzlicher Parasit ohne Daten, der dadurch verursacht wird, dass Sie mit der Krankheit Ihres "Lehrers" infiziert sind. Erkenne es als solches an und erlaube dir die volle geistige Leistungsfähigkeit, die Gott dir gegeben hat (beachte, dass ich dich nicht auffordere, isoliert oder fragmentiert oder abstrakt zu denken, alle Elemente in einer Datenbank müssen miteinander integriert werden). Erstellen Sie einen echten Schlüssel aus den Daten und nur aus den Daten. In diesem Fall gibt es nur einen möglichen Schlüssel:(name_last, name_first).

  2. Probieren Sie diesen Code aus , erklären eine eindeutige Einschränkung für die Daten:

         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
    

    Jetzt haben wir Zeileneindeutigkeit . Das ist die Reihenfolge, die den meisten Menschen passiert:Sie erstellen eine Datei, die Duplikate erlaubt; sie haben keine Ahnung, warum Dupes in den Drop-down-Menüs erscheinen; der Benutzer schreit; sie optimieren die Datei und fügen einen Index hinzu, um Duplikate zu verhindern; Sie gehen zum nächsten Bugfix. (Sie können dies richtig tun oder nicht, das ist eine andere Geschichte.)

  3. Die zweite Ebene. Für denkende Menschen, die über die Fix-its hinausdenken. Da wir jetzt Zeileneindeutigkeit haben, was in Himmels Namen ist der Zweck der ID Feld, warum haben wir es überhaupt ??? Oh, weil der Chihuahua Rotty heißt und wir Angst haben, ihn anzufassen.

    Die Deklaration, dass es sich um einen PRIMARY KEY handelt ist falsch, aber es bleibt und verursacht Verwirrung und falsche Erwartungen. Der einzige echte Schlüssel, den es gibt, ist der (name_last, name_fist), und es ist ein alternativer Schlüssel an dieser Stelle.

    Daher die ID Feld ist völlig überflüssig; ebenso der Index, der dies unterstützt; und das blöde AUTOINCREMENT auch; ebenso die falsche Deklaration, dass es sich um einen PRIMARY KEY handelt; und alle Erwartungen, die Sie daran haben, sind falsch.

    Entfernen Sie daher die überflüssige ID Feld. Probieren Sie diesen Code aus :

        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
    

    Funktioniert einwandfrei, funktioniert wie beabsichtigt, ohne die überflüssigen Felder und Indizes.

    Bitte denken Sie daran, und machen Sie es jedes Mal richtig.

Falsche Lehrer

In diesen Endzeiten werden wir, wie empfohlen, viele davon haben. Beachten Sie gut, die "Lehrer", die ID verbreiten Spalten verstehen aufgrund der detaillierten Beweise in diesem Beitrag das Relationale Modell einfach nicht oder relationale Datenbanken. Vor allem diejenigen, die Bücher darüber schreiben.

Wie sich zeigt, stecken sie in der ISAM-Technologie von vor 1970 fest. Das ist alles, was sie verstehen, und das ist alles, was sie lehren können. Sie verwenden einen SQL-Datenbankcontainer, um den Zugriff, die Wiederherstellung, das Backup usw. zu erleichtern, aber der Inhalt ist ein reines Datensatzablagesystem ohne relationale Integrität, Leistung oder Geschwindigkeit. AFAIC, es ist ein schwerer Betrug.

Zusätzlich zu ID Natürlich gibt es mehrere Elemente, die Schlüsselkonzepte von Relational oder nicht sind, die mich zusammengenommen zu einer so schwerwiegenden Schlussfolgerung veranlassen. Diese anderen Elemente würden den Rahmen dieses Beitrags sprengen.

Ein bestimmtes Idiotenpaar greift derzeit die First Normal Form an. Sie gehören in die Anstalt.

Antwort

Nun zum Rest Ihrer Frage.

Gibt es eine Möglichkeit, eine relationale Tabelle zu erstellen, ohne die Auto-Increment-Funktionen zu verlieren?

Das ist ein in sich widersprüchlicher Satz. Ich hoffe, Sie werden anhand meiner Erklärung verstehen, dass relationale Tabellen keine Notwendigkeit haben für AUTOINCREMENT "Merkmale"; wenn die Datei AUTOINCREMENT hat , es ist keine relationale Tabelle.

AUTOINCREMENT ist nur für eine Sache gut:wenn, und nur wenn, Sie eine Excel-Tabelle im SQL-Datenbank-Container erstellen möchten, vollgestopft mit Feldern namens A, B, und C, über die Oberseite und Rekordnummern auf der linken Seite. Datenbanktechnisch ist das das Ergebnis eines SELECT, einer abgeflachten Ansicht der Daten, also nicht die Quelle von Daten, die organisiert (normalisiert) sind.

Eine andere mögliche (aber nicht bevorzugte) Lösung könnte darin bestehen, dass es einen anderen Primärschlüssel in der ersten Tabelle gibt, der der Benutzername des Benutzers ist, natürlich nicht mit einer Autoinkrement-Anweisung. Ist es unvermeidlich?

In der technischen Arbeit kümmern wir uns nicht um Vorlieben, denn das ist subjektiv und ändert sich ständig. Wir kümmern uns um technische Korrektheit, denn das ist objektiv und ändert sich nicht.

Ja, es ist unvermeidlich. Denn es ist nur eine Frage der Zeit; Anzahl der Fehler; Anzahl der „Geht nicht“; Anzahl von Benutzerschreien, bis Sie sich den Tatsachen stellen, Ihre falschen Erklärungen überwinden und Folgendes erkennen:

  • der einzige Weg, um sicherzustellen, dass der Benutzer zeilen einzigartig sind, dass user_names einzigartig sind, ist ein UNIQUE zu deklarieren Einschränkung darauf

  • und user_id loswerden oder id in der Benutzerdatei

  • was für user_name wirbt zu PRIMARY KEY

Ja, denn dein gesamtes Problem mit dem dritten Tisch ist nicht zufällig damit beseitigt.

Diese dritte Tabelle ist eine assoziative Tabelle . Der einzige erforderliche Schlüssel (Primärschlüssel) ist eine Zusammensetzung der beiden übergeordneten Primärschlüssel. Das stellt die Eindeutigkeit der Zeilen sicher , die durch ihre Schlüssel identifiziert werden, nicht durch ihre IDs.

Ich warne Sie davor, weil dieselben "Lehrer" Ihnen den Fehler beigebracht haben, ID zu implementieren Felder, lehren den Fehler der Implementierung von ID Felder in der Assoziativtabelle, wo sie, genau wie bei einer gewöhnlichen Tabelle, überflüssig ist, keinen Zweck erfüllt, Duplikate einführt und Verwirrung stiftet. Und es ist doppelt überflüssig, weil die beiden Schlüssel, die uns versorgen, bereits da sind und uns ins Gesicht starren.

Da sie den RM nicht verstehen , oder relationale Begriffe, nennen sie assoziative Tabellen „Link“- oder „Map“-Tabellen. Wenn sie eine ID haben Feld, sie sind eigentlich Dateien.

Nachschlagetabellen

ID Felder sind besonders Dumme Sache für Nachschlage- oder Referenztabellen. Die meisten von ihnen haben erkennbare Codes, es besteht keine Notwendigkeit, die Liste der darin enthaltenen Codes aufzuzählen, da die Codes eindeutig sind (sein sollten).

Außerdem ist es eine gute Sache, die Codes in den untergeordneten Tabellen als FKs zu haben:Der Code ist viel aussagekräftiger und erspart oft einen unnötigen Join:

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

statt:

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

oder schlimmer:

    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

Beachten Sie, dass dies etwas ist, was man nicht vermeiden kann:Sie brauchen Eindeutigkeit im Suchcode und Einzigartigkeit in der Beschreibung. Das ist die einzige Methode, um Duplikate in jedem zu verhindern der beiden Spalten:

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

        CONSTRAINT PK 
            PRIMARY KEY ( gender_code )

        CONSTRAINT AK 
            UNIQUE ( name )
        )

Vollständiges Beispiel

Aufgrund der Details in Ihrer Frage vermute ich, dass Sie Probleme mit der SQL-Syntax und der FK-Definition haben, daher werde ich die gesamte Lösung, die Sie benötigen, als Beispiel geben (da Sie keine Dateidefinitionen angegeben haben):

    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 )
        )

Dort der PRIMARY KEY Deklaration ist ehrlich, es ist ein Primärschlüssel; keine ID; kein AUTOINCREMENT; keine zusätzlichen Indizes; keine doppelten Zeilen; keine falschen Erwartungen; keine Folgeprobleme.

Datenmodell

Hier ist das Datenmodell für die Definitionen.

  • Beispiel für ein Benutzer-Sportdatenmodell

  • Wenn Sie nicht an die Notation gewöhnt sind, beachten Sie bitte, dass jedes kleine Häkchen, jede Kerbe und Markierung, die durchgezogenen vs. gestrichelten Linien, die quadratischen vs. runden Ecken, etwas sehr Spezifisches bedeutet. Siehe IDEF1X-Notation .

  • Ein Bild sagt mehr als tausend Worte; in diesem Fall ist ein Standard-Reklamationsbild mehr wert; ein schlechter ist das Papier nicht wert, auf dem er gezeichnet ist.

  • Bitte überprüfen Sie die Verbphrasen sorgfältig, sie bestehen aus einer Reihe von Prädikaten. Der Rest der Prädikate kann direkt aus dem Modell bestimmt werden. Wenn dies nicht klar ist, fragen Sie bitte nach.