Sign in Join

Live chat for Free Pascal, Lazarus, Delphi and every Pascal programmer.

Mailing lists / fpc-pascal / 2011-10

How to insert a record and get the primary key with sqldb?

61 messages · 13 people · –

Reply by email Subscribe to this list Your subscription

Read-only archive. Use j and k to move between messages.

Felipe Monteiro de Carvalho

Hello,

Yet another chapter of my database problems =)

Ok, now I want to insert a record in my table and I would like to obtain the auto-generated PrimaryKey

I tryed a number of options:

  SQLGameSession.Insert();
  SQLGameSession.Edit;
  SQLGameSession.FieldByName('GameEvent').AsInteger := lGameEventId;
  SQLGameSession.Post;

This one just failed silently. Nothing was added to the database, no idea why. I had done a SELECT * FROM WHERE which selected nothing. Should I instead make a full selection of the table? Isn't that very inneficient for just inserting 1 record? (My app is already very slow in the database connection as my profiling shows)

And another attempt:

  DBComm.SQLTransaction.StartTransaction; <-- Fails here with
"transaction already active"
  SQLText := Format('INSERT INTO "GameSession" (GameEvent, TableId)
values (%d, %d);', [lGameEventId, ARequest.GameId]);
  DBComm.PQConnection.ExecuteDirect(SQLText);
  DBComm.SQLTransaction.Commit;

Not to mention that in this second way I would have no idea how to obtain the primary key...

any suggestions welcome.

thanks,

Felipe Monteiro de Carvalho
Felipe Monteiro de Carvalho
to Felipe Monteiro de Carvalho

Hello,

Ok, searching some more I see that "select scope_identity()" could return the generated primary key. But how to get the value?

 DBComm.PQConnection.ExecuteDirect(SQLText);

The method above has no return value =(

Felipe Monteiro de Carvalho
Unknown author
to Felipe Monteiro de Carvalho: Yet another chapter of my database problems =) Ok, now I want to insert a record in my…
Felipe Monteiro de Carvalho wrote 11 lines
Hello, Yet another chapter of my database problems =) Ok, now I want to insert a record in my table and I would like to obtain the auto-generated PrimaryKey I tryed a number of options: SQLGameSession.Insert(); SQLGameSession.Edit;

Remove this call. Edit must be called to edit an existing record.

SQLGameSession.FieldByName('GameEvent').AsInteger := lGameEventId; SQLGameSession.Post;

You should add ApplyUpdates. Post posts the changes in the internal memory buffer; Nothing is saved to the database untill you call ApplyUpdates.

Show quoted text 11 lines
This one just failed silently. Nothing was added to the database, no idea why. I had done a SELECT * FROM WHERE which selected nothing. Should I instead make a full selection of the table? Isn't that very inneficient for just inserting 1 record? (My app is already very slow in the database connection as my profiling shows) And another attempt: DBComm.SQLTransaction.StartTransaction; <-- Fails here with "transaction already active"

Correct. The default transaction is made active after connecting. You should call StartTransaction on this transaction only after a commit or rollback.

Show quoted text 5 lines
SQLText := Format('INSERT INTO "GameSession" (GameEvent, TableId) values (%d, %d);', [lGameEventId, ARequest.GameId]); DBComm.PQConnection.ExecuteDirect(SQLText); DBComm.SQLTransaction.Commit;

It's not recommended to use ExecuteDirect. Instead do a

With TSQLQuery.Create(Self) Do
   try
     Database:=MyDatabase;
     Transaction:=MyDatabase.SQLTransaction;
     SQL.Text:='INSERT INTO "GameSession" (GameEvent, TableId) values (:EventID, :GameId);';
     ParamByName('GameEvent).AsInteger:=lGameEventId;
     ParamByName('GameID').AsInteger:=ARequest.GameId;
     ExecSQL;
     (Transaction as TSQLTransaction).Commit;
   finally
     Free;
   end;

The use of parameters is recommended, it avoids SQL injection.

Not to mention that in this second way I would have no idea how to obtain the primary key...

By reading the just created record, see my reply from yesterday. If the table uses a sequence, first get the new sequence value, and then do the insert with the generated value.

Didn't you get a copy of the Lazarus book ? There is a whole chapter on database programming with Lazarus. All the above is explained there.

Michael.

Marco van de Voort
to Felipe Monteiro de Carvalho: Yet another chapter of my database problems =) Ok, now I want to insert a record in my…

In our previous episode, Felipe Monteiro de Carvalho said:

Ok, now I want to insert a record in my table and I would like to obtain the auto-generated PrimaryKey

This is a classic problem, since SQL simply doesn't support this.

So all DBs do something else, for postgresql there are sequence objects that can be queried, while other allow to return the id of the autogenerated fields.

Afaik sqldb does not abstract this yet.

Unknown author
to Marco van de Voort
Marco van de Voort wrote 11 lines
In our previous episode, Felipe Monteiro de Carvalho said: > Ok, now I want to insert a record in my table and I would like to > obtain the auto-generated PrimaryKey This is a classic problem, since SQL simply doesn't support this. So all DBs do something else, for postgresql there are sequence objects that can be queried, while other allow to return the id of the autogenerated fields. Afaik sqldb does not abstract this yet.

That's because it can't be abstracted correctly. There are 2 incompatible mechanisms.

1. autogenerated fields (mysql, MS SQL server) which must be retrieved after the insert using a special API.

2. or sequences, which must be generated manually before the insert (DB2, Oracle, Firebird) using a special API, but which may or may not be generated in an AFTER INSERT trigger. In which case it's impossible to retrieve the sequence value after the insert except by re-reading the record.

I don't know which mechanism postgresql follows.

Michael.

Unknown author
to Felipe Monteiro de Carvalho: Ok, searching some more I see that "select scope_identity()" could return the generated…
Felipe Monteiro de Carvalho wrote 8 lines
Hello, Ok, searching some more I see that "select scope_identity()" could return the generated primary key. But how to get the value?  DBComm.PQConnection.ExecuteDirect(SQLText); The method above has no return value =(

Use a TSQLQuery with SQL "select scope_identity() as theid" and read field 0.

I repeat, do not use ExecuteDirect.

Michael.

Inoussa OUEDRAOGO
to Felipe Monteiro de Carvalho: Ok, searching some more I see that "select scope_identity()" could return the generated…
Ok, searching some more I see that "select scope_identity()" could return the generated primary key. But how to get the value?

Better use the RETURNING* clause** as it clearly state the column value you are expecting; The "scope_identity()" may be a source of subtle bugs that are
difficult to resolve, for example :
what if the table make use of two sequences (yes sometime this is needed) what if the table's insert trigger generates a insert query(or stored procedure) into another table which make use of sequence

(*) http://www.postgresql.org/docs/8.3/interactive/sql-insert.html
(**) this clause is at least supported by Firebird, MS SQL SERVER, ORACLE
Inoussa O.
Martin Schreiber
to Marco van de Voort: In our previous episode, Felipe Monteiro de Carvalho said: This is a classic problem,…
Marco van de Voort wrote 11 lines
In our previous episode, Felipe Monteiro de Carvalho said: > Ok, now I want to insert a record in my table and I would like to > obtain the auto-generated PrimaryKey This is a classic problem, since SQL simply doesn't support this. So all DBs do something else, for postgresql there are sequence objects that can be queried, while other allow to return the id of the autogenerated fields. Afaik sqldb does not abstract this yet.

MSEgui updates inserted primary key fields automatically for MySQL and SQLite3 by "lastinsertid". IIRC sqldb does the same?
For database which support the "returning" clause tmse*field.providerflags1 pf1_refreshinsert and pf1_refreshupdate can be used, this works for all fields.

Martin

Michael Van Canneyt
to Martin Schreiber
Martin Schreiber wrote 15 lines
On Saturday 22 October 2011 15.21:40 Marco van de Voort wrote: > In our previous episode, Felipe Monteiro de Carvalho said: >> Ok, now I want to insert a record in my table and I would like to >> obtain the auto-generated PrimaryKey > > This is a classic problem, since SQL simply doesn't support this. > > So all DBs do something else, for postgresql there are sequence objects > that can be queried, while other allow to return the id of the > autogenerated fields. > > Afaik sqldb does not abstract this yet. MSEgui updates inserted primary key fields automatically for MySQL and SQLite3 by "lastinsertid". IIRC sqldb does the same?

Not to my knowledge.
It stores the lastinsertid in the cursor, but this is not made available to the programmer.

For database which support the "returning" clause tmse*field.providerflags1 pf1_refreshinsert and pf1_refreshupdate can be used, this works for all fields.

Hardly an abstraction, it's just some automatisms :-)

But good to know.
We should really overhaul sqldb and add some of the MSEgui features.

Thanks, Martin.

Michael.

Felipe Monteiro de Carvalho
to Unknown author: That's because it can't be abstracted correctly. There are 2 incompatible mechanisms. 1.…
Show quoted text 5 lines
2. or sequences, which must be generated manually before the insert (DB2, Oracle, Firebird) using a special   API, but which may or may not be generated in an AFTER INSERT trigger.   In which case it's impossible to retrieve the sequence value after the insert except by re-reading the record.

Indeed, it looks like that Postgres uses this second method, because I did this:

  SQLText:='INSERT INTO "GameSession" ("GameEvent", "TableId") values
(:GameEventParam, :TableIdParam);';
  SQLGameSession.SQL.Text := SQLText;
  SQLGameSession.Params.ParamByName('GameEventParam').AsInteger:=lGameEventId;
  SQLGameSession.Params.ParamByName('TableIdParam').AsInteger:=ARequest.GameId;
  SQLGameSession.ExecSQL;
  DBComm.SQLTransaction.Commit;
  SQLGameSession.Active := True;

And I get a message saying that my value for SessionId is missing ... but I thought it would be auto-generated, because I created my table like this:

CREATE TABLE "GameSession" (
"SessionId" bigint NOT NULL,
"GameEvent" bigint NOT NULL,
"TableId" bigint NOT NULL
);

ALTER TABLE public."GameSession" OWNER TO postgres;

CREATE SEQUENCE "GameSession_SessionId_seq"
START WITH 1
INCREMENT BY 1
NO MAXVALUE
NO MINVALUE

    CACHE 1;
ALTER TABLE public."GameSession_SessionId_seq" OWNER TO postgres;
ALTER SEQUENCE "GameSession_SessionId_seq" OWNED BY "GameSession"."SessionId";
-- Not sure what this does
-- SELECT pg_catalog.setval('"GameEvent_Id_seq"', 1, true);
ALTER TABLE ONLY "GameSession"
    ADD CONSTRAINT "GameSession_pkey" PRIMARY KEY ("SessionId");

Note that I did not invest this stuff ... I just copied from stuff to create other tables which were already in the project.

Felipe Monteiro de Carvalho
Michael Van Canneyt
to Felipe Monteiro de Carvalho
Felipe Monteiro de Carvalho wrote 44 lines
On Sat, Oct 22, 2011 at 3:33 PM, wrote: > 2. or sequences, which must be generated manually before the insert (DB2, > Oracle, Firebird) using a special >   API, but which may or may not be generated in an AFTER INSERT trigger. >   In which case it's impossible to retrieve the sequence value after the > insert except by re-reading the record. Indeed, it looks like that Postgres uses this second method, because I did this: SQLText:='INSERT INTO "GameSession" ("GameEvent", "TableId") values (:GameEventParam, :TableIdParam);'; SQLGameSession.SQL.Text := SQLText; SQLGameSession.Params.ParamByName('GameEventParam').AsInteger:=lGameEventId; SQLGameSession.Params.ParamByName('TableIdParam').AsInteger:=ARequest.GameId; SQLGameSession.ExecSQL; DBComm.SQLTransaction.Commit; SQLGameSession.Active := True; And I get a message saying that my value for SessionId is missing ... but I thought it would be auto-generated, because I created my table like this: CREATE TABLE "GameSession" ( "SessionId" bigint NOT NULL, "GameEvent" bigint NOT NULL, "TableId" bigint NOT NULL ); ALTER TABLE public."GameSession" OWNER TO postgres; CREATE SEQUENCE "GameSession_SessionId_seq" START WITH 1 INCREMENT BY 1 NO MAXVALUE NO MINVALUE CACHE 1; ALTER TABLE public."GameSession_SessionId_seq" OWNER TO postgres; ALTER SEQUENCE "GameSession_SessionId_seq" OWNED BY "GameSession"."SessionId"; -- Not sure what this does -- SELECT pg_catalog.setval('"GameEvent_Id_seq"', 1, true);

Sets the initial value of the sequence.

Show quoted text 6 lines
ALTER TABLE ONLY "GameSession" ADD CONSTRAINT "GameSession_pkey" PRIMARY KEY ("SessionId"); Note that I did not invest this stuff ... I just copied from stuff to create other tables which were already in the project.

You must get a value first, and pass it along to the insert statement.

Auto-generation is not possible, since you don't have any link between the sequence and your table. (normally, this is done in the trigger).

Michael.

Marco van de Voort
to Unknown author: That's because it can't be abstracted correctly. There are 2 incompatible mechanisms. 1.…

In our previous episode, said:

Show quoted text 20 lines
>> Ok, now I want to insert a record in my table and I would like to >> obtain the auto-generated PrimaryKey > > This is a classic problem, since SQL simply doesn't support this. > > So all DBs do something else, for postgresql there are sequence objects that > can be queried, while other allow to return the id of the autogenerated > fields. > > Afaik sqldb does not abstract this yet. That's because it can't be abstracted correctly. There are 2 incompatible mechanisms. 1. autogenerated fields (mysql, MS SQL server) which must be retrieved after the insert using a special API. 2. or sequences, which must be generated manually before the insert (DB2, Oracle, Firebird) using a special API, but which may or may not be generated in an AFTER INSERT trigger. In which case it's impossible to retrieve the sequence value after the insert except by re-reading the record. I don't know which mechanism postgresql follows.

A combination. Autogenerated, but the API call that the value must be obtained from is basically the sequence object. (which also has different operations).

Afaik Zeos manages to abstract this for all these dbs by having a sequence object.

Martin Schreiber
to Michael Van Canneyt: Sets the initial value of the sequence. You must get a value first, and pass it along to…
Michael Van Canneyt wrote 9 lines
> > Note that I did not invest this stuff ... I just copied from stuff to > create other tables which were already in the project. You must get a value first, and pass it along to the insert statement. Auto-generation is not possible, since you don't have any link between the sequence and your table. (normally, this is done in the trigger).

BTW, MSEgui has tsequencelink which fetches a sequence value and stores it in the field by posting a inserted record automatically. Works for Firebird and Postgres.

Martin

Michael Van Canneyt
to Marco van de Voort: In our previous episode, said: A combination. Autogenerated, but the API call that the…
Marco van de Voort wrote 27 lines
In our previous episode, said: >>> Ok, now I want to insert a record in my table and I would like to >>> obtain the auto-generated PrimaryKey >> >> This is a classic problem, since SQL simply doesn't support this. >> >> So all DBs do something else, for postgresql there are sequence objects that >> can be queried, while other allow to return the id of the autogenerated >> fields. >> >> Afaik sqldb does not abstract this yet. > > That's because it can't be abstracted correctly. There are 2 incompatible mechanisms. > > 1. autogenerated fields (mysql, MS SQL server) which must be retrieved after the insert using a special API. > > 2. or sequences, which must be generated manually before the insert (DB2, Oracle, Firebird) using a special > API, but which may or may not be generated in an AFTER INSERT trigger. > In which case it's impossible to retrieve the sequence value after the insert except by re-reading the record. > > I don't know which mechanism postgresql follows. A combination. Autogenerated, but the API call that the value must be obtained from is basically the sequence object. (which also has different operations). Afaik Zeos manages to abstract this for all these dbs by having a sequence object.

I fail to see how it can do that. E.g. the mechanism by Martin is just a trick to update a field value after an insert/update. That's a fine/useful mechanism, but not what I'd call 'abstracting'.

But never mind. I think the trick is useful, and we should look into getting it in SQLDB.

Michael.

Michael Van Canneyt
to Martin Schreiber: BTW, MSEgui has tsequencelink which fetches a sequence value and stores it in the field…
Martin Schreiber wrote 13 lines
On Saturday 22 October 2011 16.20:13 Michael Van Canneyt wrote: >> >> Note that I did not invest this stuff ... I just copied from stuff to >> create other tables which were already in the project. > > You must get a value first, and pass it along to the insert statement. > > Auto-generation is not possible, since you don't have any link between > the sequence and your table. (normally, this is done in the trigger). > BTW, MSEgui has tsequencelink which fetches a sequence value and stores it in the field by posting a inserted record automatically. Works for Firebird and Postgres.

Indeed. IBX has a similar feature. One more for the TODO list.

Michael.

Ludo Brands
to Michael Van Canneyt: I fail to see how it can do that. E.g. the mechanism by Martin is just a trick to update…
Show quoted text 12 lines
> Afaik Zeos manages to abstract this for all these dbs by having a > sequence object. I fail to see how it can do that. E.g. the mechanism by Martin is just a trick to update a field value after an insert/update. That's a fine/useful mechanism, but not what I'd call 'abstracting'. But never mind. I think the trick is useful, and we should look into getting it in SQLDB.

Zeos TZSequence is only supported for Oracle, IB and PostGreSql, ie. the databases using sequences. AFAIK, the use of TZSequence is also mutually exclusive with a trigger that uses that sequence. When using a trigger the RETURNING clause is the solution to use. A very limited abstraction...

Ludo

Marcos Douglas
to Unknown author: Remove this call. Edit must be called to edit an existing record. You should add…
Show quoted text 8 lines
> >  DBComm.SQLTransaction.StartTransaction; <-- Fails here with > "transaction already active" Correct. The default transaction is made active after connecting. You should call StartTransaction on this transaction only after a commit or rollback.

I also found this problem when I migrated from Zeos to SQLdb. Only SQLdb works in this way. IMHO, it not make sense. For automatic transactions, the user can define AutoCommit=True If it is False, I can call StartTransaction BEFORE the Commit. That is the way that all libs work.

Marcos Douglas

Marcos Douglas
to Inoussa OUEDRAOGO: Better use the RETURNING* clause** as it clearly state the column value you are…
Inoussa OUEDRAOGO wrote 13 lines
> Ok, searching some more I see that "select scope_identity()" could > return the generated primary key. But how to get the value? Better use the RETURNING* clause** as it clearly state the column value you are expecting; The "scope_identity()" may be a source of subtle bugs that are difficult to resolve, for example :  what if the table make use of two sequences (yes sometime this is needed)  what if the table's insert trigger generates a insert query(or stored procedure) into another table which make use of sequence (*) http://www.postgresql.org/docs/8.3/interactive/sql-insert.html (**) this clause is at least supported by Firebird, MS SQL SERVER, ORACLE

Talking about MSSQL Server, the scope_identity() return the ID inside the scope, ie, return the ID from your INSERT instruction, ignoring Triggers, for example.
If you use @@IDENTITY then you get the last ID inserted, ie, if you have triggers you do not know which ID belongs which table.

Marcos Douglas

Felipe Monteiro de Carvalho
to Marcos Douglas

ugh, any ideas how I can obtain the next sequence value using sqldb and postgres then?

I have never used sequence values before, and while I am googling I only found either answers which are specific for a particular framework (java, djambo, whatever) or people claiming that it should generate the index automatically! o.O Which clearly it is not doing... I couldn't yet get a generic answer using SQL supported by Postgres, or whatever thing which I could reuse in sqldb.

thanks,

Felipe Monteiro de Carvalho -- Felipe Monteiro de Carvalho
Marcos Douglas
to Felipe Monteiro de Carvalho
Felipe Monteiro de Carvalho wrote 9 lines
ugh, any ideas how I can obtain the next sequence value using sqldb and postgres then? I have never used sequence values before, and while I am googling I only found either answers which are specific for a particular framework (java, djambo, whatever) or people claiming that it should generate the index automatically! o.O Which clearly it is not doing... I couldn't yet get a generic answer using SQL supported by Postgres, or whatever thing which I could reuse in sqldb.

You can use:
- Stored Procedures (SP): one for each table;
- "Dynamic SP": pass the generic SQL to the SP and return the scope_identity();
- GUID: Use a column to save a GUID. The real ID can be autoincrement but you do not need it. You can found the register using the GUID.

Marcos Douglas

Michael Van Canneyt
to Felipe Monteiro de Carvalho: ugh, any ideas how I can obtain the next sequence value using sqldb and postgres then? I…
Felipe Monteiro de Carvalho wrote 9 lines
ugh, any ideas how I can obtain the next sequence value using sqldb and postgres then? I have never used sequence values before, and while I am googling I only found either answers which are specific for a particular framework (java, djambo, whatever) or people claiming that it should generate the index automatically! o.O Which clearly it is not doing... I couldn't yet get a generic answer using SQL supported by Postgres, or whatever thing which I could reuse in sqldb.

Just a use a TSQLQuery:

With TSQLQuery.Create(Self) do
   try
     Database:=MyDatabase;
     Transaction:=MyTransaction;
     // Replace sequencename with the correct name of the sequence
     SQL.Text:='SELECT nextval(''sequencename'')';
     Open;
     TheNewID:=(Fields[0] as TLargeIntField).AsLargeInt;
     close;
   finally
     free;
   end;

That's it.

Michael.

Michael Van Canneyt
to Ludo Brands: Zeos TZSequence is only supported for Oracle, IB and PostGreSql, ie. the databases using…
Ludo Brands wrote 17 lines
>> Afaik Zeos manages to abstract this for all these dbs by having a >> sequence object. > > I fail to see how it can do that. E.g. the mechanism by > Martin is just a trick to update > a field value after an insert/update. That's a fine/useful > mechanism, but not what I'd call > 'abstracting'. > > But never mind. I think the trick is useful, and we should > look into getting it in SQLDB. > Zeos TZSequence is only supported for Oracle, IB and PostGreSql, ie. the databases using sequences. AFAIK, the use of TZSequence is also mutually exclusive with a trigger that uses that sequence. When using a trigger the RETURNING clause is the solution to use. A very limited abstraction...

... And mainly the reason I think it is not abstractable... :-)

Michael.

Martin Schreiber
to Marcos Douglas: I also found this problem when I migrated from Zeos to SQLdb. Only SQLdb works in this…
Marcos Douglas wrote 14 lines
On Sat, Oct 22, 2011 at 11:21 AM, wrote: >> DBComm.SQLTransaction.StartTransaction; <-- Fails here with >> "transaction already active" > > Correct. The default transaction is made active after connecting. > You should call StartTransaction on this transaction only after a commit > or rollback. I also found this problem when I migrated from Zeos to SQLdb. Only SQLdb works in this way. IMHO, it not make sense. For automatic transactions, the user can define AutoCommit=True If it is False, I can call StartTransaction BEFORE the Commit. That is the way that all libs work.

That means there are different transactions for reading and writing? MSEgui has this option too. But what if reading and writing should be in a single transaction?

Martin

Marcos Douglas
to Martin Schreiber
Martin Schreiber wrote 18 lines
On Saturday 22 October 2011 17.23:38 Marcos Douglas wrote: > On Sat, Oct 22, 2011 at 11:21 AM,   wrote: > >>  DBComm.SQLTransaction.StartTransaction; <-- Fails here with > >> "transaction already active" > > > > Correct. The default transaction is made active after connecting. > > You should call StartTransaction on this transaction only after a commit > > or rollback. > > I also found this problem when I migrated from Zeos to SQLdb. > Only SQLdb works in this way. IMHO, it not make sense. > For automatic transactions, the user can define AutoCommit=True If it > is False, I can call StartTransaction BEFORE the Commit. That is the > way that all libs work. > That means there are different transactions for reading and writing? MSEgui has this option too. But what if reading and writing should be in a single transaction?

I'm talking about transactions for writing.

Marcos Douglas

Martin Schreiber
to Felipe Monteiro de Carvalho: ugh, any ideas how I can obtain the next sequence value using sqldb and postgres then? I…
Felipe Monteiro de Carvalho wrote 11 lines
ugh, any ideas how I can obtain the next sequence value using sqldb and postgres then? I have never used sequence values before, and while I am googling I only found either answers which are specific for a particular framework (java, djambo, whatever) or people claiming that it should generate the index automatically! o.O Which clearly it is not doing... I couldn't yet get a generic answer using SQL supported by Postgres, or whatever thing which I could reuse in sqldb. thanks,

Postgres documenatation is here:

http://www.postgresql.org/docs/manuals/
http://www.postgresql.org/docs/8.3/static/functions-sequence.html

MSEgui calls getsqlresult() with the statement
"
function tmsepqconnection.readsequence(const sequencename: string): string; begin
result:= 'select nextval(''' +sequencename+''') as res;'; end;
"
returns. Instead of the MSEgui getsqlresult() function use a tsqlquery in sqldb.

Martin

Felipe Monteiro de Carvalho
to Michael Van Canneyt: ... And mainly the reason I think it is not abstractable... :-) Michael.

Ok, thanks a lot =)

Michael Van Canneyt wrote
... And mainly the reason I think it is not abstractable... :-)

In this case I would suggest to abstract it like this:

// ASequenceName -> The name of the sequence for usage in Postgres,
etc. Ignored for MSSQL, etc.
// ARecordValues -> The values of the fields, all should be placed in
the sequence in which they exist in the table columns. nil is
accepted.
// Returns the index to the primary key
TSQLQuery.InsertNewRecordWithAutoGeneratedPrimaryKey(ASequenceName:
string; ARecordValues: array of const): Integer;

Then it will ... insert a new record with the record values that you provided and give back the primary key for it.

At least that's how I would expect it =D

For each database it would simply figure out if it needs to get the sequence number or if it will auto-generate or whatever.

Felipe Monteiro de Carvalho
Graeme Geldenhuys
to Felipe Monteiro de Carvalho: Yet another chapter of my database problems =) Ok, now I want to insert a record in my…
Felipe Monteiro de Carvalho wrote
Yet another chapter of my database problems =)

As this message thread proves, there are many issues with Auto-inc field, so simply DON'T USE THEM!

You have many alternatives, which will save you LOTS of grey hairs. Auto-Inc field are just evil, no matter which RDBMS you use.

1) Use a GUID created at the time you do the Insert. This also means you can do Master/Detail records with no ) If you must use an Integer as a primary key, then simply implement the Ambler High/Low method. Google will give you more information, but in a nutshell it works as follows: You have a "next_id" table in the database. When you application starts it reads the last used value, books out say the next 10 numbers, and update the Next_ID table. This now means you can insert 10 new records without needing to revisit the Next_ID table, and nobody else will get those 10 numbers.

Here is an example implementation as done in tiOPF2

http://tiopf.svn.sourceforge.net/viewvc/tiopf/tiOPF2/Trunk/Options/tiOIDInteger.pas?revision=2087&view=markup

Hope this helps a bit.

Regards, - Graeme - _______________________________________________ fpGUI - a cross-platform Free Pascal GUI toolkit http://fpgui.sourceforge.net
Felipe Monteiro de Carvalho
to Michael Van Canneyt: Just a use a TSQLQuery: With TSQLQuery.Create(Self) do try Database:=MyDatabase;…
Michael Van Canneyt wrote
Just a use a TSQLQuery:

Are you sure that it is really like that? My code is virtually the same as yours and I already checked everything I could come up with. Using the final "as res;" or not, checked that the sequence exists in the database, but I still get this error:

Error: <b>Preparation of query failed. (PostgreSQL: ERROR: column "GameSession_SessionId_seq" does not exist
LINE 1: prepare prepst2 as SELECT nextval("GameSession_SessionId_se...

This code:

  SQLGameSession := TSQLQuery.Create(nil);
  SQLGameSession.Transaction := DBComm.SQLTransaction;
  SQLGameSession.Database := DBComm.PQConnection;
  SQLGameSession.FieldDefs.Add('SessionId', ftLargeint);
  SQLGameSession.FieldDefs.Add('GameEvent', ftLargeint);
  SQLGameSession.FieldDefs.Add('TableId', ftInteger);
  OPDebugLn('[TGameSessionComm.CreateSessionResponse] Obtaining New
Primary Key');
  SQLGameSession.SQL.Text:='SELECT
nextval("GameSession_SessionId_seq") as res;';
  SQLGameSession.Open;
  FSessionId := (SQLGameSession.Fields[0] as TLargeIntField).AsLargeInt;
  SQLGameSession.Close;

The transaction and connection cannot be wrong because they are the same ones used for all other transactions which work fine.

Felipe Monteiro de Carvalho
Ludo Brands
to Felipe Monteiro de Carvalho
Show quoted text 6 lines
Error: <b>Preparation of query failed. (PostgreSQL: ERROR: column "GameSession_SessionId_seq" does not exist LINE 1: prepare prepst2 as SELECT nextval("GameSession_SessionId_se... SQLGameSession.SQL.Text:='SELECT nextval("GameSession_SessionId_seq") as res;';
Nextval takes a regclass as parameter, not an identifier (column). So, use
single quotes: SELECT nextval('GameSession_SessionId_seq') as res;

Ludo

Felipe Monteiro de Carvalho
to Ludo Brands
Ludo Brands wrote
Nextval takes a regclass as parameter, not an identifier (column). So, use single quotes: SELECT nextval('GameSession_SessionId_seq') as res;

But Postgres requires double quotes or else it will lowercase the entire identifier and it won't match. It seams that it moves forward if I use both types of quotes! Like this:

  OPDebugLn('[TGameSessionComm.CreateSessionResponse] Obtaining New
Primary Key');
  SQLGameSession.SQL.Text:='SELECT
nextval(''"GameSession_SessionId_seq"'') as res;';
  SQLGameSession.Open;
  FSessionId := (SQLGameSession.Fields[0] as TLargeIntField).AsLargeInt;
  SQLGameSession.Close;

But now I get a new error "Cannot open a non-select statement" o.O

Regardless of the final "as res;" being there or not.

Felipe Monteiro de Carvalho
Ludo Brands
to Felipe Monteiro de Carvalho: On Sat, Oct 22, 2011 at 5:42 PM, Michael Van Canneyt Are you sure that it is really like…
Show quoted text 18 lines
This code: SQLGameSession := TSQLQuery.Create(nil); SQLGameSession.Transaction := DBComm.SQLTransaction; SQLGameSession.Database := DBComm.PQConnection; SQLGameSession.FieldDefs.Add('SessionId', ftLargeint); SQLGameSession.FieldDefs.Add('GameEvent', ftLargeint); SQLGameSession.FieldDefs.Add('TableId', ftInteger); OPDebugLn('[TGameSessionComm.CreateSessionResponse] Obtaining New Primary Key'); SQLGameSession.SQL.Text:='SELECT nextval("GameSession_SessionId_seq") as res;'; SQLGameSession.Open; FSessionId := (SQLGameSession.Fields[0] as TLargeIntField).AsLargeInt; SQLGameSession.Close;

The space before OPDebugLn indicates other code in between? If not, you can't add fielddefs for fields that aren't going to be in the result set. I just made a small test with the table and sequence definition you provided earlier and this works for me:

var
  SQLGameSession : TSQLQuery;
  SessionId:LargeInt;
begin
  SQLGameSession := TSQLQuery.Create(nil);
  SQLGameSession.Transaction := SQLTransaction1;
  SQLGameSession.Database := PQConnection1;
  SQLGameSession.SQL.Text:='SELECT nextval(''"GameSession_SessionId_seq"'')
as res';
  SQLGameSession.Open;
  SessionId := (SQLGameSession.Fields[0] as TLargeIntField).AsLargeInt;
  SQLGameSession.Close;
  SQLGameSession.SQL.Text:='INSERT INTO "GameSession" ("SessionId",
"GameEvent", "TableId") values (:SessionId,:EventID, :GameId)';
  SQLGameSession.ParamByName('SessionId').AsInteger:=SessionId;
  SQLGameSession.ParamByName('EventID').AsInteger:=234;
  SQLGameSession.ParamByName('GameID').AsInteger:=123;
  SQLGameSession.ExecSQL;
  (SQLGameSession.Transaction as TSQLTransaction).Commit;
  SQLGameSession.Free;
end;

Ludo

Felipe Monteiro de Carvalho
to Felipe Monteiro de Carvalho

Hello,

Ok, I figured it out =D The cannot open non-select error was not for that line! It was for something else afterwards =D I can get the next primary key correctly now =D

I am writing a CGI WebServer, so I haven't yet managed to get Lazarus step-by-step debugging to work (not sure if it is possible with CGI), so that's what caused so much confusion for me ....

thanks everyone,

Felipe Monteiro de Carvalho
Michael Van Canneyt
to Felipe Monteiro de Carvalho
Felipe Monteiro de Carvalho wrote 9 lines
Hello, Ok, I figured it out =D The cannot open non-select error was not for that line! It was for something else afterwards =D I can get the next primary key correctly now =D I am writing a CGI WebServer, so I haven't yet managed to get Lazarus step-by-step debugging to work (not sure if it is possible with CGI), so that's what caused so much confusion for me ....

You cannot debug CGI. If you want to debug a web-based app, use FastCGI or the embedded webserver.

Michael.

Graeme Geldenhuys
to Felipe Monteiro de Carvalho: Ok, I figured it out =D The cannot open non-select error was not for that line! It was…
Felipe Monteiro de Carvalho wrote
I am writing a CGI WebServer, so I haven't yet managed to get Lazarus step-by-step debugging to work (not sure if it is possible with CGI), so that's what caused so much confusion for me ....

You can't do that. You have to use an embedded web server (good luck with that too - I'm trying to do something similar now). Alternatively, use the dbugintf.pp unit and send messages to the debug server, or use tiOPF2's tiLog unit and send debug data to File, Debug Server, Event Handler etc.

Regards, - Graeme - _______________________________________________ fpGUI - a cross-platform Free Pascal GUI toolkit http://fpgui.sourceforge.net
Reinier Olislagers
to Unknown author: That's because it can't be abstracted correctly. There are 2 incompatible mechanisms. 1.…
Show quoted text 28 lines
On Sat, 22 Oct 2011, Marco van de Voort wrote: > In our previous episode, Felipe Monteiro de Carvalho said: >> Ok, now I want to insert a record in my table and I would like to >> obtain the auto-generated PrimaryKey > > This is a classic problem, since SQL simply doesn't support this. > > So all DBs do something else, for postgresql there are sequence > objects that > can be queried, while other allow to return the id of the autogenerated > fields. > > Afaik sqldb does not abstract this yet. That's because it can't be abstracted correctly. There are 2 incompatible mechanisms. 1. autogenerated fields (mysql, MS SQL server) which must be retrieved after the insert using a special API. 2. or sequences, which must be generated manually before the insert (DB2, Oracle, Firebird) using a special API, but which may or may not be generated in an AFTER INSERT trigger. In which case it's impossible to retrieve the sequence value after the insert except by re-reading the record.

Correct, but for option 2. - at least in Firebird - BEFORE INSERT triggers are often used, not AFTER INSERT.
See eg http://www.firebirdfaq.org/faq29/

Also, using INSERT...RETURNING it's very well possible to get the sequence value directly when inserting the data.

What's more incompatible to me is the difference between: a. manually having to specify a PK, either totally manually or using a sequence
b. having the DB do it for you, either via an autonumber (your option 1) or a trigger with a sequence.

The problem is that I think it's very difficult to SQLDB to figure out whether it's in situation a or b. If in a and the DB supports sequences, SQLDB will still need to be told which sequence to use.

If in b, we face all the various ways of getting an autonumber or auto-generated PKs back, see e.g.
https://secure.wikimedia.org/wikipedia/en/wiki/Insert_%28SQL%29#Retrieving_the_key

When in b, we then get the issue of getting the primary key:

Doing it in one statement:
INSERT RETURNING for Firebird, Postgresql, Oracle, ....? ...

In two:
SCOPY_IDENTITY() for SQL Server 2000 and earlier, or if you don't/can't use OUTPUT
LAST_INSERT_ID()
Special select statement for DB2
....

;)

Unknown author
to Reinier Olislagers
Reinier Olislagers wrote 33 lines
On 22-10-2011 15:33, wrote: > > > On Sat, 22 Oct 2011, Marco van de Voort wrote: > >> In our previous episode, Felipe Monteiro de Carvalho said: >>> Ok, now I want to insert a record in my table and I would like to >>> obtain the auto-generated PrimaryKey >> >> This is a classic problem, since SQL simply doesn't support this. >> >> So all DBs do something else, for postgresql there are sequence >> objects that >> can be queried, while other allow to return the id of the autogenerated >> fields. >> >> Afaik sqldb does not abstract this yet. > > That's because it can't be abstracted correctly. There are 2 > incompatible mechanisms. > > 1. autogenerated fields (mysql, MS SQL server) which must be retrieved > after the insert using a special API. > > 2. or sequences, which must be generated manually before the insert > (DB2, Oracle, Firebird) using a special > API, but which may or may not be generated in an AFTER INSERT trigger. > In which case it's impossible to retrieve the sequence value after > the insert except by re-reading the record. Correct, but for option 2. - at least in Firebird - BEFORE INSERT triggers are often used, not AFTER INSERT. See eg http://www.firebirdfaq.org/faq29/

Typo on my part, sorry.

Also, using INSERT...RETURNING it's very well possible to get the sequence value directly when inserting the data.

Yes, but not all DBs support this. We use Firebird a lot, and it didn't support that construct until version 2.1 or so.

In each case: it's hard to abstract correctly, but nevertheless we'll try and make managing this easier. Martin's ideas for this are useful.

What's funny is that I never understood how the MySQL/SQL-Server way could correctly work. For example I have 2 tables, both with an auto-incremental field.
Table 1 has an after insert trigger that does an extra insert in table 2. When I do an insert in table 1 , what does 'last_insert_id' return ? The value for table 2 or table 1 ?
The last inserted id for your connection is the one for table 2, but you need/expect the last id for table 1 :-)

Michael.

Ludo Brands
to Unknown author
Show quoted text 11 lines
What's funny is that I never understood how the MySQL/SQL-Server way could correctly work. For example I have 2 tables, both with an auto-incremental field. Table 1 has an after insert trigger that does an extra insert in table 2. When I do an insert in table 1 , what does 'last_insert_id' return ? The value for table 2 or table 1 ? The last inserted id for your connection is the one for table 2, but you need/expect the last id for table 1 :-)

Before MySQL 5.0.12 last_insert_id returns table 2, since 5.0.12 table 1. Triggers were introduced in 5.0.2.

SQLServer's SCOPE_IDENTITY() returns table 1 (the trigger is out of scope) and @@IDENTITY returns 2.

Ludo

Unknown author
to Ludo Brands
Ludo Brands wrote 18 lines
> What's funny is that I never understood how the > MySQL/SQL-Server way could correctly work. For example I have > 2 tables, both with an auto-incremental field. > Table 1 has an after insert trigger that does an extra insert > in table 2. > When I do an insert in table 1 , what does 'last_insert_id' return ? > The value for table 2 or table 1 ? > The last inserted id for your connection is the one for table > 2, but you > need/expect the last id for table 1 :-) > Before MySQL 5.0.12 last_insert_id returns table 2, since 5.0.12 table 1. Triggers were introduced in 5.0.2. SQLServer's SCOPE_IDENTITY() returns table 1 (the trigger is out of scope) and @@IDENTITY returns 2.

This mess is why I prefer sequences :-)

Michael.

Mark Morgan Lloyd
to Unknown author
Show quoted text 8 lines
> Before MySQL 5.0.12 last_insert_id returns table 2, since 5.0.12 table 1. > Triggers were introduced in 5.0.2. > > SQLServer's SCOPE_IDENTITY() returns table 1 (the trigger is out of > scope) > and @@IDENTITY returns 2. This mess is why I prefer sequences :-)

:-) I had to tackle this one with PostgreSQL about ten years ago. I don't know whether sequences weren't implemented at the time or if I was simply too unfamiliar with the system to get things working, but I ended up generating a random primary key in the (Delphi) program that was committing the data and relying on the server to reject it if not unique.

A minor warning about Postgres's serial type: if the table is cleared the underlying sequence isn't automatically reset. That might or might not be what's needed/expected.

Mark Morgan Lloyd markMLl .AT. telemetry.co .DOT. uk [Opinions above are the author's, not those of his employers or colleagues]
Graeme Geldenhuys
to Vincent Snijders
Vincent Snijders wrote
I consider this bad advice. GUID are bad primary keys, because of their size and the fact they are not sequential by design.

We did some speed tests between GUIDs (Char(36) as used by tiOPF which strips some chars from a normal GUID) and Int, String type primary keys. Yes GUID's were slightly slower, but not by a margin that the end-user would notice.

The convenience of having a truly unique primary key even across databases and having the primary key available before the data is inserted into a database, far outweighed the cons. At least for us.

Regarding your comment about sequential primary keys. In my opinion, it is highly debatable if PK should be in a sequential order or if its values should in any way be related to the data or not. I strongly believe it shouldn't relate to the data at all, just like I believe a primary key must not consist of multiple data fields. To me, a database is simply a storage location for my data. Primary Keys are simple part of the data structure a database uses to retrieve my data.

Anyway, I have no intention to debate this further. The internet is full of such message threads already. As I said, based on our needs, GUID's was a perfect fit.

Regards,
- Graeme -

fpGUI Toolkit - a cross-platform GUI toolkit using Free Pascal http://fpgui.sourceforge.net/
Marcos Douglas
to Vincent Snijders: 2011/10/22 Graeme Geldenhuys : their size and the fact they are not sequential by design.…
Vincent Snijders wrote 7 lines
2011/10/22 Graeme Geldenhuys : > 1) Use a GUID created at the time you do the Insert. This also means > you can do Master/Detail records with no problems at all. I consider this bad advice. GUID are bad primary keys, because of their size and the fact they are not sequential by design.

GUID isn't the key, but a way to know how get the register before insert it.

Marcos Douglas

Graeme Geldenhuys
to Marcos Douglas
Marcos Douglas wrote
GUID isn't the key, but a way to know how get the register before insert it.

In our case we use the actual GUID value as the actual primary key. The GUID is unique in our database and across multiple databases. This is very important to us, because we merge multiple databases (250+) into one large database on a monthly basis for data analysis and statistics.

eg: Here is a insert statement our application would have generated.

INSERT INTO ADDRESS (OID, OWNER_OID, ADDRESSTYPE_OID, LINES, CITY, PROVINCE, POSTCODE, COUNTRY_OID) VALUES
('CDB0C8A3-8AB7-42E9-BC12-6C3B48A3EEB0',
'FCE0EB83-9DED-4DEA-92A2-60504A8C2912',
'C30AE79B-CD60-49D1-AB4C-76C8BD08AC7E', 'PO BOX 2617', 'SOMERSETWEST', '', '7129', 'ZA');

We also use the actual data fields for things like sorting, filtering etc., not the primary key. The end-user will never ever see the GUID in the application UI.

Regards,
- Graeme -

fpGUI Toolkit - a cross-platform GUI toolkit using Free Pascal http://fpgui.sourceforge.net/
Reinier Olislagers
to Unknown author: Typo on my part, sorry. Yes, but not all DBs support this. We use Firebird a lot, and it…
Show quoted text 6 lines
On Mon, 24 Oct 2011, Reinier Olislagers wrote: > Also, using INSERT...RETURNING it's very well possible to get the > sequence value directly when inserting the data. Yes, but not all DBs support this. We use Firebird a lot, and it didn't support that construct until version 2.1 or so.

Yep, it's one of many really nice cross-db incompatibilities. Long live SQL ;)

In each case: it's hard to abstract correctly, but nevertheless we'll try and make managing this easier. Martin's ideas for this are useful.

Yes, he's got experience with it already - more than you can say of some armchair theorists like me ;)

Show quoted text 8 lines
What's funny is that I never understood how the MySQL/SQL-Server way could correctly work. For example I have 2 tables, both with an auto-incremental field. Table 1 has an after insert trigger that does an extra insert in table 2. When I do an insert in table 1 , what does 'last_insert_id' return ? The value for table 2 or table 1 ? The last inserted id for your connection is the one for table 2, but you need/expect the last id for table 1 :-)

True. Fortunately, I've never needed to do that ;)

Regards,
Reinier

Unknown author
to Vincent Snijders: 2011/10/22 Graeme Geldenhuys : their size and the fact they are not sequential by design.…
Vincent Snijders wrote 6 lines
2011/10/22 Graeme Geldenhuys : > 1) Use a GUID created at the time you do the Insert. This also means > you can do Master/Detail records with no problems at all. I consider this bad advice. GUID are bad primary keys, because of their size and the fact they are not sequential by design.

You just discarded most Microsoft product designs =-) They use GUIDs all over the place :-)

Michael.

Vincent Snijders
to Unknown author

2011/10/24 :

Show quoted text 14 lines
On Mon, 24 Oct 2011, Vincent Snijders wrote: > 2011/10/22 Graeme Geldenhuys : >> >> 1) Use a GUID created at the time you do the Insert. This also means >> you can do Master/Detail records with no problems at all. > > I consider this bad advice. GUID are bad primary keys, because of > their size and the fact they are not sequential by design. You just discarded most Microsoft product designs =-) They use GUIDs all over the place :-)

Still, I won't use them as primary (clustered) key in Microsoft sql server. If the business rules require a guid, it may become a unique key in the table, but not a primary key.

Vincent

Marco van de Voort
to Unknown author: You just discarded most Microsoft product designs =-) They use GUIDs all over the place…

In our previous episode, said:

Show quoted text 5 lines
> I consider this bad advice. GUID are bad primary keys, because of > their size and the fact they are not sequential by design. You just discarded most Microsoft product designs =-) They use GUIDs all over the place :-)

At least they designed them in when they were still unique. (based on Mac address)

Henry Vermaak
to Marco van de Voort
Marco van de Voort wrote 9 lines
In our previous episode, said: >> I consider this bad advice. GUID are bad primary keys, because of >> their size and the fact they are not sequential by design. > > You just discarded most Microsoft product designs =-) > They use GUIDs all over the place :-) At least they designed them in when they were still unique. (based on Mac address)

It's pretty easy to spoof mac addresses?

Henry

Unknown author
to Vincent Snijders: 2011/10/24 : Still, I won't use them as primary (clustered) key in Microsoft sql server.…
Vincent Snijders wrote 19 lines
2011/10/24 : > > > On Mon, 24 Oct 2011, Vincent Snijders wrote: > >> 2011/10/22 Graeme Geldenhuys : >>> >>> 1) Use a GUID created at the time you do the Insert. This also means >>> you can do Master/Detail records with no problems at all. >> >> I consider this bad advice. GUID are bad primary keys, because of >> their size and the fact they are not sequential by design. > > You just discarded most Microsoft product designs =-) > They use GUIDs all over the place :-) Still, I won't use them as primary (clustered) key in Microsoft sql server. If the business rules require a guid, it may become a unique key in the table, but not a primary key.

As a rule, I don't use GUIDs at all; Same arguments as you seem to have.

And, very important but often underestimated:
At least our clients can read an integer primary/foreign key aloud over the phone when the need arises. I can't hear them doing that with a GUID :-)

Michael.

Reinier Olislagers
to Henry Vermaak: It's pretty easy to spoof mac addresses? Henry
Henry Vermaak wrote
On 24/10/11 13:05, Marco van de Voort wrote: > In our previous episode, > said:

<snip discussion on GUID primary keys.

Henry

Summary:
1. A lot of (or some) people don't like GUID PKs
2. Some (or a lot of) people do.

Regardless of being in camp 1 or 2, I think FPC should recognize that both 1. and 2. are used in practice.
Of course, if developers don't want to contribute code to support 2, that remains there prerogative ;)

I think Graeme was right in not posting any further; this is one of the subjects that can lead to holy wars :)

Regards,
Reinier

Unknown author
to Reinier Olislagers
Reinier Olislagers wrote 14 lines
On 24-10-2011 14:23, Henry Vermaak wrote: > On 24/10/11 13:05, Marco van de Voort wrote: >> In our previous episode, >> said: <snip discussion on GUID primary keys. > Henry Summary: 1. A lot of (or some) people don't like GUID PKs 2. Some (or a lot of) people do. Regardless of being in camp 1 or 2, I think FPC should recognize that both 1. and 2. are used in practice. Of course, if developers don't want to contribute code to support 2, that remains there prerogative ;)

We will of course support GUID PKs, although in my opinion, there is precious little to support as it will in general be client code that generates the GUID (unless I am much mistaken in what is common practise) ?

Michael.

Marco van de Voort
to Henry Vermaak: It's pretty easy to spoof mac addresses? Henry

In our previous episode, Henry Vermaak said:

Show quoted text 7 lines
>> You just discarded most Microsoft product designs =-) >> They use GUIDs all over the place :-) > > At least they designed them in when they were still unique. (based on Mac > address) It's pretty easy to spoof mac addresses?

True, but that goes more in the direction of security hazard, which is a different kind of problem then primary key in a DB.

Ludo Brands
to Unknown author: We will of course support GUID PKs, although in my opinion, there is precious little to…
Show quoted text 17 lines
> Summary: > 1. A lot of (or some) people don't like GUID PKs > 2. Some (or a lot of) people do. > > Regardless of being in camp 1 or 2, I think FPC should recognize that > both 1. and 2. are used in practice. Of course, if developers don't > want to contribute code to support 2, that remains there prerogative > ;) We will of course support GUID PKs, although in my opinion, there is precious little to support as it will in general be client code that generates the GUID (unless I am much mistaken in what is common practise) ?

Most databases have functions to create GUID's (with different randomness quality and different storage requirements):

SQLServer: NEWID()
MySQL: uuid()
Oracle:SYS_GUID()

Using these functions has the same problems as sequences: retrieve the key.

Sqldb is missing ftguid support for most databases leaving the user with the conversion to TGUID. Fe Oracle returns GUID's as RAW(32) and mysql as aaaaaaaa-bbbb-cccc-dddd-eeeeeeeeeeee

Ludo

Graeme Geldenhuys
to Unknown author: As a rule, I don't use GUIDs at all; Same arguments as you seem to have. And, very…
And, very important but often underestimated: At least our clients can read an integer primary/foreign key aloud over the phone when the need arises. I can't hear them doing that with a GUID :-)

Enable client-side logging (our apps have a checkbox for this), and ask them to reproduce the error, then email the log file to you.

Our users are mostly ex school teachers, they know near zero about computers, so they wouldn't have the foggiest idea of what I am talking about when I ask them to quote the primary key. ;-)

Why is your clients seeing primary key field values anyway? (Unless you primary keys are part of the data display in the UI I guess).

Regards,
- Graeme -

fpGUI Toolkit - a cross-platform GUI toolkit using Free Pascal http://fpgui.sourceforge.net/
Graeme Geldenhuys
to Unknown author: We will of course support GUID PKs, although in my opinion, there is precious little to…
We will of course support GUID PKs, although in my opinion, there is precious little to support as it will in general be client code that generates the GUID (unless I am much mistaken in what is common practise) ?

That is indeed the case. There is nothing extra that needs to be added to SqlDB. Our primary key fields are simply a varchar(36), and we all know a string value / varchar() is already well supported. ;-)

Regards,
- Graeme -

fpGUI Toolkit - a cross-platform GUI toolkit using Free Pascal http://fpgui.sourceforge.net/
Graeme Geldenhuys
to Ludo Brands: Most databases have functions to create GUID's (with different randomness quality and…
Ludo Brands wrote
Most databases have functions to create GUID's (with different randomness quality and different storage requirements):

No, no, no... you are missing the point of this thread, and what I meant by using a GUID. The idea is that you can created the GUID values client-side before you insert any data into the database, thus you don't have the issue Felipe mentioned in his origin post (how to reliably find the primary key after you posted the record). Using GUID's on client-side, you simply don't have that ,
- Graeme -

fpGUI Toolkit - a cross-platform GUI toolkit using Free Pascal http://fpgui.sourceforge.net/
Unknown author
to Graeme Geldenhuys: Enable client-side logging (our apps have a checkbox for this), and ask them to reproduce…
Graeme Geldenhuys wrote 9 lines
On 2011-10-24 14:25, wrote: > > And, very important but often underestimated: > At least our clients can read an integer primary/foreign key aloud over the > phone when the need arises. I can't hear them doing that with a GUID :-) Enable client-side logging (our apps have a checkbox for this), and ask them to reproduce the error, then email the log file to you.

That won't help at all.

Our users are mostly ex school teachers, they know near zero about computers, so they wouldn't have the foggiest idea of what I am talking about when I ask them to quote the primary key. ;-)

Of course we don't tell them to "quote the primary key" but we tell them 'Please add the LB_ID column to the grid and tell us the value for the record".

Why is your clients seeing primary key field values anyway? (Unless you primary keys are part of the data display in the UI I guess).

They don't see them as a matter of course.

But often the only way to correctly identify a record is the primary key. And then it helps if this is an integer, not a GUID.

But now we're getting way off topic.

Michael.

Ludo Brands
to Graeme Geldenhuys: No, no, no... you are missing the point of this thread, and what I meant by using a GUID.…
Show quoted text 12 lines
> > Most databases have functions to create GUID's (with different > randomness quality and different storage requirements): No, no, no... you are missing the point of this thread, and what I meant by using a GUID. The idea is that you can created the GUID values client-side before you insert any data into the database, thus you don't have the issue Felipe mentioned in his origin post (how to reliably find the primary key after you posted the record). Using GUID's on client-side, you simply don't have that problem at all.

I did understand how you use GUID values :) But it is not the only way to use GUID's as PK and Reinier was wondering about guid support, in general. Some SQLServer users like to use "Id UNIQUEIDENTIFIER not null DEFAULT newsequentialid()" field definitions.

Ludo

Marcos Douglas
to Graeme Geldenhuys: No, no, no... you are missing the point of this thread, and what I meant by using a GUID.…
Graeme Geldenhuys wrote 12 lines
On 2011-10-24 15:15, Ludo Brands wrote: > > Most databases have functions to create GUID's (with different randomness > quality and different storage requirements): No, no, no... you are missing the point of this thread, and what I meant by using a GUID. The idea is that you can created the GUID values client-side before you insert any data into the database, thus you don't have the issue Felipe mentioned in his origin post (how to reliably find the primary key after you posted the record). Using GUID's on client-side, you simply don't have that was I said, but I think that nobody read.

Marcos Douglas