Avatar billede retep Nybegynder
10. marts 2001 - 16:54 Der 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.

På forhånd tak
Retep
Avatar billede pellelil Nybegynder
11. marts 2001 - 09:10 #1
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.
Avatar billede agermose Nybegynder
11. marts 2001 - 11:06 #2
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
Avatar billede retep Nybegynder
11. marts 2001 - 13:10 #3
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.

Mvh
Retep
Avatar billede agermose Nybegynder
11. marts 2001 - 13:43 #4
transactioner er låsemekanismer. Idet du starter en transaction, sikre du at den værdi du læser som max(id) er den værdi du indsatte med gen_id.
Avatar billede pellelil Nybegynder
11. marts 2001 - 14:09 #5
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\" !? 
Avatar billede agermose Nybegynder
11. marts 2001 - 14:33 #6
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.
Avatar billede retep Nybegynder
18. marts 2001 - 22:20 #7
Tak for svarene! ;)
Avatar billede Ny bruger Nybegynder

Din løsning...

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.

Loading billede Opret Preview
Kategori
Computerworld tilbyder specialiserede kurser i database-management

Log ind eller opret profil

Hov!

For at kunne deltage på Computerworld Eksperten skal du være logget ind.

Det er heldigvis nemt at oprette en bruger: Det tager to minutter og du kan vælge at bruge enten e-mail, Facebook eller Google som login.

Du kan også logge ind via nedenstående tjenester