10. marts 2001 - 16:54Der er
5 kommentarer og 2 løsninger
Sidst indsatte id
Hejsa ;)
Når jeg indsætter et id i en tabel, bliver id\'et genereret af trigger og generator. Men jeg skal bruge id\'et igen til indsættelse i andre tabeller. Så mit spørgsmål er hvordan får jeg id\'et ud igen.
Jeg har tidligere brugt MySQL hvor jeg har låst tabellen og brugt MySQL funktionen last_insert_id. Er der tilsvarende muligheder i Interbase?
Hvis der ikke er en tilsvarende funktion må det være muligt at spørge på max(id) men så skal jeg stadig bruge kommandoerne til at låse og låse op...
Jeg udvikler i både PHP og Delphi, hvis I vil give et eksempel.
Jeg tvivler på at du kan returnere det sidste tildelte ID, og hvis du kunne så er det ikke en god methode. I et flerbruger miljø kan du \"risikere\" at en anden person i mellem tiden også har fået tildelt et nummer så når du beder om at få det seneste tildelte nummer så får du ikke \"dit eget\" men det der blev tildelt en anden bruger/maskine.
I stedet for at lade din trigger \"kalde\" generatoren, så kan du lave en Stored Procedure (SP) som returnere et (generator) nummer som du selv (fra Delphi) fylder i alle de poster hvor du har brug for det. I mine triggere der kigger jeg om ID feltet er udfyldt hvis det ikke er så lader jeg triggeren generere en ellers bruger jeg den jeg får fra delphi. I dit tilfælde ville jeg vælge at kalde en SP fra Delphi og så fra Delphi udfylde alle ID felterne i de poster hvor du har brug for det.
En trigger ville så se ud som flg. <SNIP> CREATE TRIGGER ONBEFOREINSERT_USERS FOR USERS ACTIVE BEFORE INSERT POSITION 0 as begin /* Set USERID if not allready set */ if ((new.USERID_DB is null) or (new.USERID_DB = 0)) then new.USERID_DB = gen_id(GEN_USERS_USERID, 1); end </SNIP>
Proceduren ville se ud som flg.: <SNIP> CREATE PROCEDURE PROC_ID_GEN_USERS ( NUMBERS_TO_GENERATE INTEGER) RETURNS ( ID INTEGER) AS BEGIN ID = Gen_id(GEN_USERS_USERID, NUMBERS_TO_GENERATE); SUSPEND; END </SNIP>
Som du kan se så overføre jeg parametren \"NUMBERS_TO_GENERATE\" jeg kan således fra mit Delphi program generere (allokere) 10 på hinanden følgende numre hvis jeg på forhånd ved at jeg skal gemme 10 poster med hver sit nummer.
der er to rimelige muligheder 1) du bruger din trigger som sædvanlig, og laver efterfølgende en select på \"max(id) from mytable\". Dette skal selvfølgelig så foregå i en --transaction--
ibase_trans(); ibase_...(\"insert into ..:\"); $id = ibase....(\"select max(id) id from mytable\"); ibase_commit();
2) du laver en storedprocedure, der laver en insert for dig, og returnere det id, som din post blev indsat med.
den sidste er nok den hurtigste, men også den mindst fleksible. Du skal også vælge enten 2.1) forhindre inserts direkte på tabellen 2.2) have en trigger i stil med andet svar, til det tilfælde hvor der indsættes uden om din procedure
Er det ikke muligt at låse en tabel som i MySQL? Derved kan jeg sikre mig at jeg får det rigtige id ud efter indsættelsen ved brug af max(). Måske ikke den mest optimale løsning, men så slipper jeg for at ændre en hel masse.
agermose> At du laven en transaktion er ikke nok i sig selv. Det at lave en transaktion er ikke det sammen som at du låser tabellen. så du vil stadig risikere at en anden har indsat en post således at det ikke er dit egen id du får tilbage.
Jeg er rimelig sikker på at Retep bruger IBX (?), og i så fald skal du kigge på transaktionens \"Isolation layer\". Jeg bruger normal \"Read Commited\" hvilket betyder at du kan se hvad andre har commited efter din egen transaktion startede. Dette vil helt sikkert betyde at placere din Insert/Max i samme transaktion ikke vil give den ønskede effekt. Muligvis hvis du i stedet sætter \"isolation layer\" til \"Snapshot\" !?
InterBase 6 default isolation layer ER snapshot! Jeg regner med at driveren til php IKKE ændre på dette. Det er måske en fejl? Og man kan selvfølgelig altid sætte dette eksplicit.
Det er klart at mit forslag IKKE virker, hvis man ikke bruger snapshot transactions.
Tilladte BB-code-tags: [b]fed[/b] [i]kursiv[/i] [u]understreget[/u] Web- og emailadresser omdannes automatisk til links. Der sættes "nofollow" på alle links.