Lazarus

Programming => Databases => Topic started by: Leledumbo on December 19, 2010, 04:04:02 pm

Title: Getting last insert id (ZEOS or SQLdb)
Post by: Leledumbo on December 19, 2010, 04:04:02 pm
I can't find this implemented in ZEOS or SQLdb. I wonder why, isn't this functionality is easy to implement? Currently I create my own:
Code: [Select]
function LastInsertID(const TableName: String): Integer;
begin
  with DBQuery do begin
    SQL.Text := 'SELECT MAX(id) AS last_insert_id FROM :TableName';
    Params.ParamByName('TableName').AsString := TableName;
    Open;
    Result := FieldByName('last_insert_id').AsInteger;
  end;
end;
but I really wish to have this implemented because I almost always use MV(C|P|???) design pattern and this is required for newly created table entry.
Title: Re: Getting last insert id (ZEOS or SQLdb)
Post by: clauslack on December 19, 2010, 05:28:25 pm
For Firebird (and others)
you can use insert an return primary key in one step, with RETURNING clause.

with DBQuery do begin
    SQL.Text := 'INSERT INTO t1 (...) values (...) returning pk';
    Open;
    Result := FieldByName('pk').AsInteger;
  end;


Tested with Firebird 2.1.4 and fpc  2.3.1 (SQLDB)

Regards

Title: Re: Getting last insert id (ZEOS or SQLdb)
Post by: Leledumbo on December 19, 2010, 06:41:12 pm
I've never heard of that. How portable it is across dbms?
Title: Re: Getting last insert id (ZEOS or SQLdb)
Post by: clauslack on December 19, 2010, 11:15:20 pm
"Firebird 2 introduces RETURNING clause for INSERT statements...."
http://www.firebirdfaq.org/faq243/

Postgre
http://www.postgresql.org/docs/current/interactive/sql-insert.html

Oracle
http://psoug.org/snippet/INSERT-With-Returning-Clause_595.htm
(Stored procedure)
http://www.adp-gmbh.ch/ora/sql/insert_into_x_returning_y.html

I don't know about other DBMS.

I only test with Firebird and SQLDb.
Title: Re: Getting last insert id (ZEOS or SQLdb)
Post by: cdbc on December 20, 2010, 09:20:07 pm
Hi.
Within Firebird, it's portable.

hth - Regards Benny
Title: Re: Getting last insert id (ZEOS or SQLdb)
Post by: Leledumbo on December 21, 2010, 03:41:21 am
Weird, Firebird states that it's supported so we can get it like MySQL did. But MySQL doesn't support this clause... so, for safety (because I still don't know the environment of deployment platform), I still use my LastInsertID above.
Title: Re: Getting last insert id (ZEOS or SQLdb)
Post by: Lacak2 on December 21, 2010, 07:25:49 am
Some of APIs (for example SQLite, MySQL) provides functions to obtain last value (currently inserted) of identity (autoincrement) columns.

There is it internaly in dbSQL also implemented (search for example for "insertid" in sources in fcl-db directory), but not all SQL connectors provide such information.

General solution will be IMHO fetch this "last identity value" after Append...Post and put into local dataset. See also http://bugs.freepascal.org/view.php?id=16076
Title: Re: Getting last insert id (ZEOS or SQLdb)
Post by: clauslack on December 21, 2010, 03:18:12 pm
Check this,
 In firebird (maybe other DBMS)
 the primary key has ascending order, and the statement
 select max(id) don't use this index.  So in tables of millions of records,
 this query has a high resources consuming, unless you create a descending index in primary key field.

Regards
Title: Re: Getting last insert id (ZEOS or SQLdb)
Post by: Leledumbo on December 21, 2010, 03:27:57 pm
Quote
Check this,
 In firebird (maybe other DBMS)
 the primary key has ascending order, and the statement
 select max(id) don't use this index.  So in tables of millions of records,
 this query has a high resources consuming, unless you create a descending index in primary key field.
Hmm... do you have any other solution? Should I differ the query based on TZConnection.Protocol?
Title: Re: Getting last insert id (ZEOS or SQLdb)
Post by: marcov on December 21, 2010, 04:29:34 pm
For Zeos, use the TZSequence object.  I use it succesfully with Postgresql.

(but note that it might not be safe with automatic transactions)

Title: Re: Getting last insert id (ZEOS or SQLdb)
Post by: Marc on December 22, 2010, 05:12:18 pm
set the AutoGenerateValue of the ID field to arAutoInc, then zeos will update this value
(for postgre you need to set it to arDefault)
Title: Re: Getting last insert id (ZEOS or SQLdb)
Post by: Leledumbo on December 23, 2010, 12:06:23 am
Quote
For Zeos, use the TZSequence object.
How to use it? I only see Connection property...
Quote
set the AutoGenerateValue of the ID field to arAutoInc, then zeos will update this value
(for postgre you need to set it to arDefault)
of what object?

FYI, since I use fpWeb to create this application, I must create the code by hand (dropping the component from palette causes the app to end up in runtime errors).
Title: Re: Getting last insert id (ZEOS or SQLdb)
Post by: marcov on December 23, 2010, 12:27:48 am
Quote
For Zeos, use the TZSequence object.
How to use it? I only see Connection property...

If a table is named xxx and there is a field "ID" that been declared PK and autonumber etc in postgres, then there is a sequence counter in postgresql named "xxx_ID_seq"

Enter this into the tzsequence object, and also connect it to connection. You can then put this sequence object in the relevant query, and connect the navigator to it.

This should be doable in code too, but these are mainly interesting if you use e.g. dbnavigators. I don't know how fpweb solves that.
Title: Re: Getting last insert id (ZEOS or SQLdb)
Post by: Leledumbo on December 23, 2010, 03:45:46 am
Quote
If a table is named xxx and there is a field "ID" that been declared PK and autonumber etc in postgres, then there is a sequence counter in postgresql named "xxx_ID_seq"
Is "ID" name hardcoded? I've used that, but in lowercase (all my table fields do). Would that be a problem?
Quote
This should be doable in code too, but these are mainly interesting if you use e.g. dbnavigators. I don't know how fpweb solves that.
I see TZSequence has GetNextValue, so probably I can call that from code.
Title: Re: Getting last insert id (ZEOS or SQLdb)
Post by: Marc on December 23, 2010, 10:10:33 am
Quote
set the AutoGenerateValue of the ID field to arAutoInc, then zeos will update this value
(for postgre you need to set it to arDefault)
of what object?

The ID field. (Now speaking delphi, haven't used this in lazarus) If you have a TZQuery, and you make the fields of it Persistent, you can change the properties of the ID field.

If you create the query in code, then you can access the property by:
  yourQuery.FieldByName('ID').AutoGenerateValue := arAutoInc
Title: Re: Getting last insert id (ZEOS or SQLdb)
Post by: marcov on December 23, 2010, 01:41:47 pm
Quote
If a table is named xxx and there is a field "ID" that been declared PK and autonumber etc in postgres, then there is a sequence counter in postgresql named "xxx_ID_seq"
Is "ID" name hardcoded? I've used that, but in lowercase (all my table fields do). Would that be a problem?

No.Where I put ID, the name of the PK field is placed. Of course the case has to match, but it doesn't even have to be "id" at all afaik, that is just tradition. The PK bit matters, and the pgadmin tool creates the corresponding <tablename>_<fpfield>_seq

Quote
This should be doable in code too, but these are mainly interesting if you use e.g. dbnavigators. I don't know how fpweb solves that.
I see TZSequence has GetNextValue, so probably I can call that from code.
[/quote]

I think you need the _current_ value to get the last emitted value.
Title: Re: Getting last insert id (ZEOS or SQLdb)
Post by: Leledumbo on December 23, 2010, 04:01:47 pm
Quote
If you create the query in code, then you can access the property by:
  yourQuery.FieldByName('ID').AutoGenerateValue := arAutoInc
Ah... now I see. It's a property of TField. Thanks, I'll try.
Quote
I think you need the _current_ value to get the last emitted value.
Err... OK.
Title: Re: Getting last insert id (ZEOS or SQLdb)
Post by: SteveF on December 23, 2010, 07:45:44 pm
Quote
For Zeos, use the TZSequence object.
How to use it? I only see Connection property...

If a table is named xxx and there is a field "ID" that been declared PK and autonumber etc in postgres, then there is a sequence counter in postgresql named "xxx_ID_seq"

Enter this into the tzsequence object, and also connect it to connection. You can then put this sequence object in the relevant query, and connect the navigator to it.

This should be doable in code too, but these are mainly interesting if you use e.g. dbnavigators. I don't know how fpweb solves that.

Pretty much the same with Firebird, except it's not so automatic.  In Firebird they're known as "Generators".

In Firebird you need to assign the PK constraint to the relevant field, build the Generator for each PK that needs to Auto-increment, and make a Before-Insert Trigger for each table which, if the PK field of the new entry is empty or zero, asks the matching Generator for the next sequential number and puts it in the table with the new data for the other columns.

Once this is set up, the insert SQL sent by Lazarus does not need to send a PK value.  Just send all the other data columns, and the Auto-inc PK will be handled automagically by the database engine on the back side.

Alternatively, you can also interrogate the Generator directly, obtain the new PK value, and include it in the insert SQL.  If this is done scrupulously, the Trigger is not needed (but maybe still a good thing for redundancy).  Either method will work.

Steve

Title: Re: Getting last insert id (ZEOS or SQLdb)
Post by: patyi on September 21, 2011, 09:01:37 pm
Hi all, Lazarus developers !

I try this example on FPC 2.4.4 and Lazarus SVN latest with SQLDB, Firebird 2.5, Ubuntu 11.04.

with DBQuery do begin
    Close;
    SQL.Clear;
    SQL.Add( 'INSERT INTO katalog (id, name) VALUES (NULL, :name) RETURNING id');
    Params[0].AsString := 'BlaBlaBla';  //  ParamByName('name').AsString := 'BlaBlaBla';
    Open;
    Result := Fields[0].AsInteger; // FieldByName('id').AsInteger;
    Close;
 end;

After Open I got an error :  -Dynamic SQL error, - SQL error code = -504, - Invalid cursor reference, - Cursor is not open.
I also try it with latest FPC SVN 2.7.1, Lazarus latest SVN, with same result !

I'm wondering it is broken functionality on SQLDB or I miss something ?  :o

With ZeosDBO 7.0 latest SVN the result is perfectly what is expected !!!!   ;D

(sorry for my English !)

Best regards : Patyi
Title: Re: Getting last insert id (ZEOS or SQLdb)
Post by: Zoran on September 21, 2011, 11:30:26 pm
The example application I'm attaching to this post works well on FB 2.1 (tested on Win XP and Ubuntu, Lazarus from svn, fpc 2.4.4).

It uses "employee" database which comes with Firebird installation.

in windows you should find it under "C:\Program Files\Firebird\Firebird_2_1\examples\empbuild\employee.fdb.
In Ubuntu, you should decompress it, as explained in lower section of this document: http://www.firebirdsql.org/manual/ubusetup.html
Title: Re: Getting last insert id (ZEOS or SQLdb)
Post by: kodok_buncit on September 22, 2011, 05:06:02 am
The example application I'm attaching to this post works well on FB 2.1 (tested on Win XP and Ubuntu, Lazarus from svn, fpc 2.4.4).

It uses "employee" database which comes with Firebird installation.

in windows you should find it under "C:\Program Files\Firebird\Firebird_2_1\examples\empbuild\employee.fdb.
In Ubuntu, you should decompress it, as explained in lower section of this document: http://www.firebirdsql.org/manual/ubusetup.html

not work on SQLDB errod code = 504 invalid cursor reference
Title: Re: Getting last insert id (ZEOS or SQLdb)
Post by: Lacak2 on September 22, 2011, 07:53:11 am
May be that there is difference between FB 2.1 (works) and FB 2.5 (does not work) !
Title: Re: Getting last insert id (ZEOS or SQLdb)
Post by: Zoran on September 22, 2011, 08:55:33 pm
May be that there is difference between FB 2.1 (works) and FB 2.5 (does not work) !

Probably so. I have FB 2.1 on both OS-s and it works.
Title: Re: Getting last insert id (ZEOS or SQLdb)
Post by: Lacak2 on September 30, 2011, 01:42:48 pm
I can also confirm, that it is FB 2.5 related problem.
It seems, that FB 2.5 no more supports "fetching output parameters" from stored procedures or from insert/update/delete ... returning

See also related bug report http://bugs.freepascal.org/view.php?id=16236
where is attached patch.
TinyPortal © 2005-2018