[megoldva/félig] Oracle LAST_INSERT_ID()

Sziasztok!

Nem vagyok sajna eléggé tapasztalt a témában, ezért kérem a segítségeteket. Hogyan tudom azt a rekordot kivenni az adatbázisból, amit beszúrtam, és egy szekvenciával kapott primary key-t?

Eddig odáig jutottam, hogy a "SELECT seq.* FROM all_sequences seq WHERE ..." visszaadja a LAST_NUMBERT, de mivel van egy cache-ja a dolognak, így ez a szám a cachelt értéken túli első "szabad" szám. A "SELECT * FROM foo WHERE id = (select MAX(id) FROM foo)"-val az a bajom, hogy ha időközben volt másik insert, akkor nem jó rekordot kapok vissza. Próbálkoztam az "INSERT INTO ... RETURNING id INTO x" de ez nem akarta az igazságot.

Tudom széjjelrágott csont, de bénaságomból adódóan nem találok normális megoldást egy ideje.

Előre is köszi a segítségeteket.

Hozzászólások


DECLARE
  xx PLS_INTEGER;
BEGIN
  insert into ... values ...
    returning id into xx;
  dbms_output.put_line(xx);

  insert into id, ... values (seq_neve.NEXTVAL, ...);
  select seq_neve.CURRVAL INTO xx;
  dbms_output.put_line(xx);
end;

Én ezt egy hagyományos insert után szeretném használni, egy általános osztályt írok ugyanis, ami auto incrementes pk-val megáldott tábla rekordjait képes kezelni, így nem feltételezhetetek semilyen tárolt eljárást. Van a tábla meg mennek bele az adatok, nekem meg kell, amit utoljára beszúrtam. :(

java'nother blog

A szekvenciak nincsenek oszlopokhoz (mezokhoz) rendelve. A jogosultsagi rendszer adta kereteken belul akarki hasznalhatja az altaluk szolgaltatott ertekeket tetszoleges celra.
Komplex logika eseten mindez egy oszlophoz rendelt megoldasnal lenyegesen nagyobb rugalmassagot biztosit.

A szekvenciaknak csupan egy celja van: automatikus egyedi azonositok generalasa megfelelo teljesitmeny mellett, kivant szabalyok betartasaval.

Ha nagyon reverse-engineerelos kedvedben vagy, akkor a parsolt SQL utasitasok szovegebol kihamozhato, h. mely statementek, mely szekvenciakat mely oszlopok feltoltesekor hasznaljak. V$SQL v. barmely nezet jo, amely a shared_pool-ban tarolt vegrahajtasi tervekhez tartozo szoveges SQL utasitast tartalmazza. Ez nem szep megoldas, alkalmazasfejlesztes soran ne is gondolj ra, de pl. egy rendszer megismerese soran elfogadhato tajekoztato jelleggel.

Sejtettem, hogy ez lesz a bibi. Ezek szerint rövidke Oracles pályafutásom alatt rögtön belefutottam egy dologba, amit nem lehet Oracle-val megoldani :(. Olyan osztály akartam készíteni, aminek megmondod melyik táblával dolgozzon, és a tábla szerklezete alapján tud beszúrni, frissíteni, törölni, validálni, meg leválogatni rekordokat. Minden működik is kivéve azt, hogy beszúrás után visszaadja a metódus a beszúrt rekordot mégpedig úgy, hogy újra kiolvassa az adatbázisból. Az osztály MySQL-es verziója nagyon jól működött, és 80% levette az adatbázisban matatást a vállamról, ehelyett objektumokkal kellett csak dolgoznom. Oracle-ben ezek szerint legalább még a sequencia nevét tudnom kell ahhoz, hogy ugyanazt a funkcionalitást elérjem. Szomorú, persze tudom van értelme, meg a rugalmasság, de most épp a rugalmasságát vesztette el a dolog.

java'nother blog

Meg lehet oldani triggerekkel. A last_insert_id() funkcionalitáshoz
1) használod a szekvencia nevét
2) a legelső hozzászólásban látott látott "...returning id into valtozo" megoldást használod

Az se rossz, ha *egyetlen* szekvenciát használsz az egész szoftverben. Az ID-k nem lesznek olyan folyamatosak, de ez technikailag nem gond.

Upd.: ha a triggereket úgy írod meg, hogy egy globális package változóba eltárolják a legutolsó szekvencia ID-ket, akkor végül is több szekvenciát is használhatsz. Gyakorlatilag tökéletesen tudod emulálni a last_insert_id()-t.

Hát épp az a baj, hogy általános megoldást szeretnék nem akarom tudni a seq nevét, nem akarok egy seq-et használni, stb. Annyit szeretnék, mint írtam, hogy megadom a PHP osztályomnak a tábla nevét, és $newEntity = $oszt->insert($entity) és a beszúrt rekordot adja vissza úgy, hogy kiolvassa a db-ből.

java'nother blog

akkor viszont maradnak a string műveletek,
a seq neve legyen a táblanév_seq
és így valahogy :

L_EXEC := 'select '....|| ...
EXECUTE IMMEDIATE L_EXEC USING Param1, ... ;

és/vagy

cursor_name := dbms_sql.open_cursor;
dbms_sql.parse(cursor_name, 'begin :aret := ' || fv_név || '(:param1,... dbms_sql.v7);
dbms_sql.bind_variable(cursor_name, ':aret', dinaret);
..
..
result := dbms_sql.execute(cursor_name);
dbms_sql.variable_value(cursor_name, ':l_dret', dinaret);
..
..
persze ennél az a baj, ha sokan hajtják, akkor sokat parcol az oracle.

Attol fugg milyen kliens lib-et hasznalsz, altalaban mindben van tamogatas, a beszurt mezo id-nek lekerdeesere, pl. jdbc-ben van ilyen.

java.sql.Statement

public ResultSet getGeneratedKeys() throws SQLException;

Ja es ez szabvany:
In JDBC 3.0, the java.sql.DatabaseMetaData interface provides the following method:

public boolean supportsGetGeneratedKeys();