Lazarus
Programming => Databases => Topic started 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:
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.
-
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
-
I've never heard of that. How portable it is across dbms?
-
"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.
-
Hi.
Within Firebird, it's portable.
hth - Regards Benny
-
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.
-
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
-
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
-
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?
-
For Zeos, use the TZSequence object. I use it succesfully with Postgresql.
(but note that it might not be safe with automatic transactions)
-
set the AutoGenerateValue of the ID field to arAutoInc, then zeos will update this value
(for postgre you need to set it to arDefault)
-
For Zeos, use the TZSequence object.
How to use it? I only see Connection property...
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).
-
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.
-
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?
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.
-
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
-
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
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.
-
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.
I think you need the _current_ value to get the last emitted value.
Err... OK.
-
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
-
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
-
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
-
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
-
May be that there is difference between FB 2.1 (works) and FB 2.5 (does not work) !
-
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.
-
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.