Hvordan 'sette inn hvis ikke eksisterer' i MySQL?

Jeg begynte med å google, og fant denne artikkelen som snakker om mutex-tabeller.

Jeg har en tabell med ~ 14 millioner poster. Hvis jeg vil legge til flere data i samme format, er det en måte å sikre at posten jeg vil sette inn ikke allerede eksisterer uten å bruke et par spørringer (dvs. en spørring for å sjekke og en for å sette inn er resultatsettet tomt)?

Garanterer en "unik" begrensning på et felt at "innsetting" vil mislykkes hvis det allerede er der?

Det ser ut til at med bare en begrensning, når jeg utsteder innsatsen via php, kvekker skriptet.

Løsning

bruk INSERT IGNORE INTO table.

se

det finnes også INSERT ... ON DUPLICATE KEY UPDATE syntaks, du finner forklaringer på dev.mysql.com.


Innlegg fra bogdan.org.ua i henhold til Google's webcache:

  1. oktober 2007

For å starte: fra og med den nyeste MySQL, syntaks presentert i tittelen er ikke mulig. Men det er flere veldig enkle måter å oppnå det som er forventet ved hjelp av eksisterende funksjonalitet.

Det er tre mulige løsninger: å bruke INSERT IGNORE, REPLACE eller INSERT ... ON DUPLICATE KEY UPDATE.

Forestill deg at vi har en tabell:

CREATE TABLE avskrifter ( ensembl_transcript_id varchar(20) NOT NULL, transcript_chrom_start int(10) unsigned NOT NULL, transcript_chrom_end int(10) unsigned NOT NULL, PRIMÆRNØKKEL (ensembl_transcript_id) ) ENGINE=InnoDB DEFAULT CHARSET=latin1;

Forestill deg nå at vi har en automatisk pipeline som importerer transkripsjoner metadata fra Ensembl, og at pipelinen av ulike årsaker kan bli brutt når som helst. kan bli brutt på et hvilket som helst trinn i utførelsen. Dermed må vi sikre to ting: 1) gjentatte kjøringer av rørledningen vil ikke ødelegge vår database, og 2) gjentatte kjøringer vil ikke dø på grunn av 'dupliserte primærnøkkel' feil.

Metode 1: ved hjelp av REPLACE

Det er veldig enkelt:

REPLACE INTO transcripts (Erstatt i utskrifter) SET ensembl_transcript_id = 'ENSORGT00000000001', transcript_chrom_start = 12345, transcript_chrom_end = 12678;

Hvis posten eksisterer, vil den bli overskrevet; hvis den ikke eksisterer ennå eksisterer, vil den bli opprettet. Det er imidlertid ikke effektivt å bruke denne metoden for vårt tilfelle: vi trenger ikke å overskrive eksisterende poster, det er greit bare å hoppe over dem.

Metode 2: ved hjelp av INSERT IGNORE Også veldig enkelt:

INSERT IGNORE INTO transcripts (sett inn ignorere) SET ensembl_transcript_id = 'ENSORGT00000000001', transcript_chrom_start = 12345, transcript_chrom_end = 12678;

Her, hvis 'ensembl_transcript_id' allerede er til stede i databasen, vil den bli hoppet over (ignorert). (For å være mer presis, her er et sitat fra MySQL-referansehåndboken: "Hvis du bruker IGNORE nøkkelord, feil som oppstår mens du utfører INSERT-setningen, blir behandlet som advarsler i stedet. For eksempel, uten IGNORE, vil en rad som dupliserer en eksisterende UNIQUE-indeks eller PRIMARY KEY-verdi i tabellen forårsaker en duplikatnøkkelfeil, og uttalelsen avbrytes."). Hvis posten ennå ikke finnes, vil den bli opprettet.

Denne andre metoden har flere potensielle svakheter, inkludert ikke-abort av spørringen i tilfelle det oppstår et annet problem (se håndboken). Derfor bør den brukes hvis den tidligere er testet uten nøkkelordet IGNORE-nøkkelordet. ; Det er ett alternativ til: å bruke INSERT ... ON DUPLICATE KEY UPDATE (sett inn ... ved duplisert nøkkeloppdatering). syntaks, og i UPDATE-delen bare gjør ingenting, gjør noe meningsløst (tom) operasjon, som å beregne 0+0 (Geoffray foreslår å gjøre tilordningen id = id-tildeling for MySQL-optimaliseringsmotoren for å ignorere dette operasjon). Fordelen med denne metoden er at den bare ignorerer dupliserte nøkkelhendelser, og avbryter fortsatt på andre feil.

Som en siste merknad: dette innlegget ble inspirert av Xaprb. Jeg vil også anbefale å se hans andre innlegg om å skrive fleksible SQL-spørringer.

Kommentarer (16)

on duplicate key update, eller insert ignore kan være levedyktige løsninger med MySQL.


Eksempel på on duplicate key update-oppdatering basert på mysql.com.

INSERT INTO table (a,b,c) VALUES (1,2,3)
  ON DUPLICATE KEY UPDATE c=c+1;

UPDATE table SET c=c+1 WHERE a=1;

Eksempel på insert ignore basert på mysql.com.

INSERT [LOW_PRIORITY | DELAYED | HIGH_PRIORITY] [IGNORE]
    [INTO] tbl_name [(col_name,...)]
    {VALUES | VALUE} ({expr | DEFAULT},...),(...),...
    [ ON DUPLICATE KEY UPDATE
      col_name=expr
        [, col_name=expr] ... ]

Eller:

INSERT [LOW_PRIORITY | DELAYED | HIGH_PRIORITY] [IGNORE]
    [INTO] tbl_name
    SET col_name={expr | DEFAULT}, ...
    [ ON DUPLICATE KEY UPDATE
      col_name=expr
        [, col_name=expr] ... ]

Eller:

INSERT [LOW_PRIORITY | HIGH_PRIORITY] [IGNORE]
    [INTO] tbl_name [(col_name,...)]
    SELECT ...
    [ ON DUPLICATE KEY UPDATE
      col_name=expr
        [, col_name=expr] ... ]
Kommentarer (0)

Enhver enkel begrensning bør gjøre jobben, hvis et unntak er akseptabelt. Eksempler:

  • primærnøkkel hvis ikke surrogat
  • unik begrensning på en kolonne
  • unik begrensning med flere kolonner

Beklager at dette virker villedende enkelt. Jeg vet at det ser dårlig ut i forhold til lenken du deler med oss ;-(.

Men jeg gir likevel dette svaret, fordi det ser ut til å fylle behovet ditt. (Hvis ikke, kan det utløse at du oppdaterer kravene dine, noe som også vil være "en god ting" (TM)).

Redigert: Hvis en innsats vil bryte databasens unike begrensning, kastes et unntak på databasenivå, videresendt av driveren. Det vil sikkert stoppe skriptet ditt, med en feil. Det må være mulig i PHP å adressere den saken ...

Kommentarer (4)