sql >> Database >  >> RDS >> Mysql

SQL:Een relatietabel maken met 2 verschillende auto_increment

Concepten

Je hebt een aantal basisconcepten verkeerd begrepen en de moeilijkheden zijn daaruit voortgekomen. We moeten eerst de concepten aanpakken, niet het probleem zoals u het waarneemt, en bijgevolg zal uw probleem verdwijnen.

automatisch oplopende ID's, die natuurlijk primaire sleutels zijn.

Nee, dat zijn ze niet. Dat is een veel voorkomende misvatting. En er ontstaan ​​gegarandeerd problemen.

Een ID veld kan geen primaire sleutel zijn in de Engelse of technische of relationele zin.

  • Natuurlijk, in SQL kun je elke . declareren veld om een ​​PRIMARY KEY te zijn , maar dat verandert het niet op magische wijze in een primaire sleutel in de Engelse, technische of relationele zin. Je kunt een chihuahua "Rottweiller" noemen, maar dat verandert hem niet in een Rottweiller, het blijft een chihuahua. Zoals elke taal voert SQL gewoon de commando's uit die je het geeft, het begrijpt PRIMARY KEY niet om iets relationeels te betekenen, slaat het gewoon een unieke index op de kolom (of veld).

  • Het probleem is, aangezien u verklaard de ID een PRIMARY KEY zijn , jij denkt ervan als een primaire sleutel, en u kunt verwachten dat het enkele eigenschappen van een primaire sleutel heeft. Behalve de uniciteit van de ID waarde , levert het geen voordeel op. Het heeft geen van de kwaliteiten van een primaire sleutel, of wat voor soort relationele sleutel dan ook. Het is geen sleutel in de Engelse, technische of relationele zin. Door een niet-sleutel als een sleutel te verklaren, breng je jezelf alleen maar in verwarring en kom je er pas achter dat er iets vreselijk mis is als de gebruiker klaagt over duplicaten in de tabel.

Relationele tabellen moeten rij . hebben uniciteit

EEN PRIMARY KEY op een ID veld geeft geen rij uniciteit. Daarom is het geen relationele tabel die rijen bevat, en als dat niet het geval is, dan is het een bestand met records. Het heeft niet de integriteit, of kracht (in dit stadium zul je je alleen bewust zijn van de kracht van joins), of snelheid, die een tabel in een relationele database heeft.

Voer deze code uit (MS SQL 2008) en bewijs het aan jezelf. Lees dit alstublieft niet gewoon en begrijp het, en ga dan verder met het lezen van de rest van dit antwoord, deze code moet worden uitgevoerd voordat u verder leest . Het heeft genezende waarde.

    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

Merk op dat u dubbele rijen heeft . Relationele tabellen moeten unieke rijen hebben . Verder bewijs dat je geen relationele tabel hebt, of een van de kwaliteiten ervan.

Merk op dat in uw rapport het enige dat uniek is de ID . is veld, waar geen enkele gebruiker iets om geeft, geen gebruiker ziet, omdat het geen gegevens zijn, het is wat extra onzin die een of andere stomme "leraar" je vertelde om in elk bestand te zetten. Je hebt een record uniciteit maar niet rij uniciteit.

In termen van de gegevens (de echte gegevens minus de externe toevoegingen), de gegevens name_last en name_first kan bestaan ​​zonder de ID veld. Een persoon heeft een voornaam en achternaam zonder dat er een identiteitsbewijs op zijn voorhoofd is gestempeld.

Het tweede dat u gebruikt dat u in verwarring brengt, is de AUTOINCREMENT. Als u een archiveringssysteem voor records implementeert zonder relationele mogelijkheden, is het natuurlijk handig dat u de increment niet hoeft te coderen bij het invoegen van records. Maar als u een relationele database implementeert, heeft het helemaal geen zin, omdat u het nooit zult gebruiken. Er zijn veel functies in SQL die de meeste mensen nooit gebruiken.

Corrigerende actie

Dus hoe upgrade, verhoog je dat dumb_file dat vol staat met dubbele rijen naar een relationele tabel, om enkele van de kwaliteiten en voordelen van een relationele tabel te krijgen? Hiervoor zijn drie stappen nodig.

  1. U moet sleutels begrijpen

    • En sinds we zijn overgegaan van ISAM-bestanden uit de jaren 70 naar het Relationele Model , moet u Relationele sleutels . begrijpen . Tenminste, als u gebruik wilt maken van de voordelen (integriteit, kracht, snelheid) van een relationele database.

    Dr. E F Cood, in zijn RM , verklaarde dat:

    een sleutel is samengesteld uit de gegevens

    en

    de rijen in een tabel moeten uniek zijn

    Uw "sleutel" bestaat niet uit de gegevens. Het is een extra, niet-gegevensparasiet, veroorzaakt door uw besmetting met de ziekte van uw "leraar". Herken het als zodanig, en gun jezelf de volledige mentale capaciteit die God je heeft gegeven (merk op dat ik je niet vraag om in geïsoleerde of gefragmenteerde of abstracte termen te denken, alle elementen in een database moeten met elkaar geïntegreerd zijn). Verzin een echte sleutel van de gegevens, en alleen uit de gegevens. In dit geval is er maar één mogelijke Sleutel:(name_last, name_first).

  2. Probeer deze code , verklaren een unieke beperking op de gegevens:

         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
    

    Nu hebben we uniekheid van rijen . Dat is de volgorde die de meeste mensen overkomt:ze maken een bestand aan dat dupes toestaat; ze hebben geen idee waarom dupes in de vervolgkeuzelijsten verschijnen; de gebruiker schreeuwt; ze tweaken het bestand en voegen een index toe om dupes te voorkomen; ze gaan naar de volgende bugfix. (Misschien doen ze dit correct of niet, dat is een ander verhaal.)

  3. Het tweede niveau. Voor denkende mensen die verder denken dan de fix-its. Aangezien we nu rij-uniekheid hebben, wat is in hemelsnaam het doel van de ID veld, waarom hebben we het zelfs ??? Oh, want de chihuahua heet Rotty en we zijn bang om hem aan te raken.

    De verklaring dat het een PRIMARY KEY . is is vals, maar het blijft en veroorzaakt verwarring en valse verwachtingen. De enige echte sleutel die er is, is de (name_last, name_fist), en het is een Alternatieve Sleutel op dit punt.

    Daarom de ID veld is totaal overbodig; en dat geldt ook voor de index die het ondersteunt; en dat geldt ook voor de stomme AUTOINCREMENT; en dat geldt ook voor de valse verklaring dat het een PRIMARY KEY . is; en alle verwachtingen die u ervan heeft, zijn onjuist.

    Verwijder daarom de overbodige ID veld. Probeer deze 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
    

    Werkt prima, werkt zoals bedoeld, zonder de vreemde velden en indices.

    Onthoud dit alstublieft en doe het elke keer goed.

Valse leraren

In deze eindtijd zullen we er, zoals geadviseerd, velen hebben. Let goed op, de "leraren" die ID . propageren kolommen, op grond van het gedetailleerde bewijs in dit bericht, het relationele model gewoon niet begrijpen of relationele databases. Vooral degenen die er boeken over schrijven.

Zoals blijkt, zitten ze vast in de ISAM-technologie van vóór 1970. Dat is alles wat ze begrijpen, en dat is alles wat ze kunnen onderwijzen. Ze gebruiken een SQL-databasecontainer, voor het gemak van toegang, herstel, back-up, enz., maar de inhoud is puur Record Filing System zonder relationele integriteit, kracht of snelheid. AFAIC, het is een ernstige fraude.

Naast ID velden, natuurlijk zijn er verschillende items die belangrijke relationele-of-niet-concepten zijn, die bij elkaar genomen ertoe leiden dat ik zo'n ernstige conclusie trek. Die andere items vallen buiten het bestek van dit bericht.

Een bepaald stel idioten voert momenteel een aanval uit op First Normal Form. Ze horen thuis in het gesticht.

Antwoord

Nu voor de rest van uw vraag.

Is er een manier waarop ik een relationele tabel kan maken zonder de functies voor automatisch verhogen te verliezen?

Dat is een zichzelf tegensprekende zin. Ik vertrouw erop dat u uit mijn uitleg zult begrijpen dat relationele tabellen niet nodig zijn voor AUTOINCREMENT "Kenmerken"; als het bestand AUTOINCREMENT . heeft , het is geen relationele tabel.

AUTOINCREMENT is maar voor één ding goed:als, en alleen als, u een Excel-spreadsheet wilt maken in de SQL-databasecontainer, vol met velden met de naam A, B, en C, over de bovenkant en noteer de nummers aan de linkerkant. In databasetermen is dat het resultaat van een SELECT, een afgeplatte weergave van de gegevens, dat is niet de bron van gegevens, die is georganiseerd (genormaliseerd).

Een andere mogelijke (maar niet geprefereerde) oplossing kan zijn dat er een andere primaire sleutel in de eerste tabel is, en dat is de gebruikersnaam van de gebruiker, natuurlijk niet met een auto-increment-statement. Is het onvermijdelijk?

In technisch werk geven we niet om voorkeuren, omdat dat subjectief is en voortdurend verandert. We geven om technische correctheid, want dat is objectief en verandert niet.

Ja, het is onvermijdelijk. Omdat het slechts een kwestie van tijd is; aantal fouten; aantal "kan niet"; aantal geschreeuw van gebruikers, totdat je de feiten onder ogen ziet, je valse verklaringen overwint en je realiseert dat:

  • de enige manier om ervoor te zorgen dat de gebruiker rijen uniek zijn, dat user_names uniek zijn, is om een ​​UNIQUE te declareren beperking ervan

  • en verwijder user_id of id in het gebruikersbestand

  • die user_name promoot naar PRIMARY KEY

Ja, want je hele probleem met de derde tafel is dan, niet toevallig, verholpen.

Die derde tabel is een Associatieve tabel . De enige vereiste sleutel (primaire sleutel) is een samenstelling van de twee bovenliggende primaire sleutels. Dat zorgt voor uniekheid van de rijen , die worden geïdentificeerd door hun sleutels, niet door hun IDs.

Ik waarschuw je daarvoor omdat dezelfde "leraren" je de fout hebben geleerd om ID te implementeren velden, leer de fout van het implementeren van ID velden in de associatieve tabel, waar deze, net als bij een gewone tabel, overbodig is, geen zin heeft, duplicaten introduceert en verwarring veroorzaakt. En het is dubbel overbodig omdat de twee sleutels die ervoor zorgen er al zijn en ons in het gezicht staren.

Omdat ze de RM . niet begrijpen , of relationele termen, noemen ze associatieve tabellen "link" of "map" tabellen. Als ze een ID . hebben veld, het zijn in feite bestanden.

Opzoektabellen

ID velden zijn bijzonder Stom ding om te doen voor opzoek- of referentietabellen. De meeste hebben herkenbare codes, het is niet nodig om de lijst met codes daarin op te sommen, omdat de codes uniek zijn (zouden moeten zijn).

Verder is het een goede zaak om de codes in de onderliggende tabellen als FK's te hebben:de code is veel zinvoller en bespaart vaak een onnodige join:

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

in plaats van:

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

of erger:

    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

Merk op dat dit iets is dat je niet kunt vermijden:je hebt uniekheid nodig in de opzoekcode en uniciteit op de beschrijving. Dat is de enige methode om duplicaten in elke te voorkomen van de twee kolommen:

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

        CONSTRAINT PK 
            PRIMARY KEY ( gender_code )

        CONSTRAINT AK 
            UNIQUE ( name )
        )

Volledig voorbeeld

Uit de details in je vraag vermoed ik dat je problemen hebt met de SQL-syntaxis en FK-definitie, dus ik zal de volledige oplossing die je nodig hebt als voorbeeld geven (aangezien je geen bestandsdefinities hebt gegeven):

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

Daar, de PRIMARY KEY verklaring is eerlijk, het is een primaire sleutel; geen ID; nee AUTOINCREMENT; geen extra indexen; geen dubbele rijen; geen verkeerde verwachtingen; geen gevolgproblemen.

Gegevensmodel

Hier is het gegevensmodel dat bij de definities past.

  • Voorbeeld gebruikerssportgegevensmodel

  • Als u niet gewend bent aan de notatie, houd er dan rekening mee dat elk klein vinkje, inkeping en merkteken, de ononderbroken versus onderbroken lijnen, de vierkante versus ronde hoeken, iets heel specifieks betekent. Raadpleeg de IDEF1X-notatie .

  • Een foto zegt meer dan duizend woorden; in dit geval is een standaard klachtfoto meer waard; een slechte is het papier niet waard waarop het is getekend.

  • Controleer de werkwoordzinnen zorgvuldig, ze bestaan ​​uit een reeks predikaten. De rest van de Predikaten kan direct uit het model worden bepaald. Als dit niet duidelijk is, vraag het dan.




  1. Een tekenreeks in een SQL Server-tabelkolom vervangen

  2. Databases en tabellen weergeven in PostgreSQL met psql

  3. NoClassDefFoundError krijgen tijdens het gebruik van Proguard en SQLcipher in Android

  4. Een subtekenreeks extraheren uit een tekenreeks in Oracle/SQLite