Thread: serial autoincrement and related table

serial autoincrement and related table

From
Milos Prudek
Date:
I have a serial autoincrement column called "idmember" in my main table
(members). This serial column is a key to a second table. A row in
"members" table corresponds to many rows in the second table.

What is the best way to discover current "idmember" value if I create a
few rows in the second table immediately after creating a row in the
first table?

I know about "select currval('members_idmember_seq') from members limit
1;" and I know that it works without requiring a commit. So it should be
safe when another user does the same operation - the autoincremented
'idmember' should not be assigned incorrectly.

My question is: is this the best practice?

Here's an example in Python:
conn=psycopg.connect(dbconnstr)
c=conn.cursor()
     # LOOP BEGINS HERE...
     Cmd = "INSERT INTO members ... VALUES (...);"
     c.execute(Cmd, Data)
     Cmd = "SELECT currval('members_idmember_seq') FROM members LIMIT 1;"
     c.execute(Cmd)
     idmember = c.fetchone()[0]
     Cmd = "INSERT INTO msg (idmember,txt) VALUES (%s,%s);"
     c.execute(Cmd,(idmember,TxtData)
     conn.commit()
     # LOOP ENDS HERE
c.close()
conn.commit()
conn.close()

--
Milos Prudek


Re: serial autoincrement and related table

From
Paul Thomas
Date:
On 17/05/2004 11:24 Milos Prudek wrote:
>    Cmd = "INSERT INTO members ... VALUES (...);"

If you want PostgreSQL to populate your idmember field with the next value
from the sequence, you need to specify the keyword DEFAULT as its value or
omit it from the INSERT list of coulumns (this assumes you have DEFAULT
nextval('members_idmember_seq') defined on the idmember column).

>     Cmd = "SELECT currval('members_idmember_seq') FROM members LIMIT 1;"

Should be :

Cmd = "SELECT currval('members_idmember_seq');"

Remember that there's no such thing as auto-increment fields in PostgreSQL
- they are SEQUENCES.
  --
Paul Thomas
+------------------------------+---------------------------------------------+
| Thomas Micro Systems Limited | Software Solutions for
Business             |
| Computer Consultants         |
http://www.thomas-micro-systems-ltd.co.uk   |
+------------------------------+---------------------------------------------+

Re: serial autoincrement and related table

From
Milos Prudek
Date:
 > If you want PostgreSQL to populate your idmember field with the next
 > value from the sequence, you need to specify the keyword DEFAULT as its
 > value or omit it from the INSERT list of coulumns (this assumes you have

I do omit it.

 > DEFAULT nextval('members_idmember_seq') defined on the idmember column).

I use CREATE TABLE "members" (idmember" SERIAL PRIMARY KEY, ...);

 > Should be :
 >
 > Cmd = "SELECT currval('members_idmember_seq');"

Ah, thanks for the shorter syntax.

 > Remember that there's no such thing as auto-increment fields in
 > PostgreSQL - they are SEQUENCES.

I know.

So, it's the best or reasonable practice(TM), isn't it?

--
Milos Prudek


Re: serial autoincrement and related table

From
Richard Huxton
Date:
Milos Prudek wrote:
> I have a serial autoincrement column called "idmember" in my main table
> (members). This serial column is a key to a second table. A row in
> "members" table corresponds to many rows in the second table.

> My question is: is this the best practice?
>
> Here's an example in Python:
> conn=psycopg.connect(dbconnstr)
> c=conn.cursor()
>     # LOOP BEGINS HERE...
>     Cmd = "INSERT INTO members ... VALUES (...);"
>     c.execute(Cmd, Data)
>     Cmd = "SELECT currval('members_idmember_seq') FROM members LIMIT 1;"

A simple "SELECT currval('members_idmember_seq');" will do it. The
sequence isn't part of the table.

>     c.execute(Cmd)
>     idmember = c.fetchone()[0]
>     Cmd = "INSERT INTO msg (idmember,txt) VALUES (%s,%s);"

Alternatively, you could rewrite this query:
"INSERT INO msg (idmember,txt) VALUES (currval('members_idmember_seq'),
%s);"

--
   Richard Huxton
   Archonet Ltd

Re: serial autoincrement and related table

From
Milos Prudek
Date:
> Alternatively, you could rewrite this query:
> "INSERT INO msg (idmember,txt) VALUES (currval('members_idmember_seq'),
> %s);"

Cool. You helped me demolish 3 lines of code with no compromise in
legibility.


--
Milos Prudek


Re: serial autoincrement and related table

From
Milos Prudek
Date:
 > Actually, if you declared idmember as SERIAL PRIMARY KEY, you could
 > just do:

I can't do that. idmember is a SERIAL PRIMARY KEY for members. Each
member can have many messages (msg table) with the same idmember column
value. See my original post.

--
Milos Prudek


Re: serial autoincrement and related table

From
Milos Prudek
Date:
 > See how there are no references to the sequence name in the application
 > code (which is, IMHO, good).

This is interesting. Thank you very much for the advice.

--
Milos Prudek


Re: serial autoincrement and related table

From
Marco Colombo
Date:
On Mon, 17 May 2004, Milos Prudek wrote:

> > Alternatively, you could rewrite this query:
> > "INSERT INO msg (idmember,txt) VALUES (currval('members_idmember_seq'),
> > %s);"
>
> Cool. You helped me demolish 3 lines of code with no compromise in
> legibility.


Actually, if you declared idmember as SERIAL PRIMARY KEY, you could
just do:

INSERT INTO msg (txt) VALUES (%s);

and it will automagically do the Right Thing (TM). Even more readable. :)

Just look at this:

marco=# create table msg (idmember serial primary key, txt text);
NOTICE:  CREATE TABLE will create implicit sequence 'msg_idmember_seq' for SERIAL column 'msg.idmember'
NOTICE:  CREATE TABLE/PRIMARY KEY will create implicit index 'msg_pkey' for table 'msg'
CREATE
marco=# \d msg
                                Table "msg"
 Attribute |  Type   |                       Modifier
-----------+---------+------------------------------------------------------
 idmember  | integer | not null default nextval('"msg_idmember_seq"'::text)
 txt       | text    |
Index: msg_pkey

marco=# insert into msg (txt) values ('some string');
INSERT 12288559 1
marco=# insert into msg (txt) values ('some other string');
INSERT 12288560 1
marco=# select * from msg;
 idmember |        txt
----------+-------------------
        1 | some string
        2 | some other string
(2 rows)


See the \d output in case you wonder where the magic lies. :)

.TM.
--
      ____/  ____/   /
     /      /       /            Marco Colombo
    ___/  ___  /   /              Technical Manager
   /          /   /             ESI s.r.l.
 _____/ _____/  _/               Colombo@ESI.it



Re: serial autoincrement and related table

From
Marco Colombo
Date:
On Mon, 17 May 2004, Milos Prudek wrote:

>
>  > Actually, if you declared idmember as SERIAL PRIMARY KEY, you could
>  > just do:
>
> I can't do that. idmember is a SERIAL PRIMARY KEY for members. Each
> member can have many messages (msg table) with the same idmember column
> value. See my original post.

Oh, sorry I got it now. Then, you may want to use currval() just as
Mr. Richard Huxton wrote. You can still play with DEFAULT of course,
but this may be more readable or not depending on your personal taste:

create table members (
idmember serial primary key,
some_data text             -- dummy data
);

create table msg (
idmember int references members default currval('members_idmember_seq'),
txt text
);

insert into members (some_data) values ('member foo');

insert into msg (txt) values ('some text for foo');
insert into msg (txt) values ('more text for foo');

insert into members (some_data) values ('member bar');

insert into msg (txt) values ('some text for bar');
insert into msg (txt) values ('more text for bar');

After i run the script, i get:

marco=# select * from members;
 idmember | some_data
----------+------------
        1 | member foo
        2 | member bar
(2 rows)

marco=# select * from msg;
 idmember |        txt
----------+-------------------
        1 | some text for foo
        1 | more text for foo
        2 | some text for bar
        2 | more text for bar
(4 rows)


See how there are no references to the sequence name in the application
code (which is, IMHO, good).

One word of warning. You can't use currval(), either explictly or
implicitly, alone in a session. You need to call nextval() first.
This is not your case, as you seem to do always an INSERT in members
before the ones in msg.

.TM.
--
      ____/  ____/   /
     /      /       /            Marco Colombo
    ___/  ___  /   /              Technical Manager
   /          /   /             ESI s.r.l.
 _____/ _____/  _/               Colombo@ESI.it