If this is your first visit, be sure to check out the FAQ by clicking the link above. You may have to register before you can post: click the register link above to proceed. To start viewing messages, select the forum that you want to visit from the selection below.

 
Go Back  dBforums > General > Database Concepts & Design > using auto-increment (identity) fields

Reply
 
LinkBack Thread Tools Search this Thread Display Modes
  #1 (permalink)  
Old 02-17-04, 16:32
akoyfman akoyfman is offline
Registered User
 
Join Date: Feb 2004
Location: USA (East Coast)
Posts: 6
Question using auto-increment (identity) fields

Problem:
----------
I inserted new record into a table. I need to use new primary key as a foreign key to insert dependent records into other table(s).

Solution for Oracle or DB2:
-------------------------------
In Oracle or DB2 there is such thing as a sequence object. I request 'nextval' from the sequence, and use it as both primary key for my primary table and foreign key for my dependent table(s).

Question:
-----------
How to do this in SQL Server, Access, MySql, etc.? These databases do not have sequences. They use auto-increment (auto-number, identity, etc.) fields. The value is assigned at the insertion time, I do not know what the value is and cannot use it as a foreign key.

Thanks in advance,

Alex
Reply With Quote
  #2 (permalink)  
Old 02-17-04, 18:48
r123456 r123456 is offline
Registered User
 
Join Date: Sep 2003
Location: The extremely Royal borough of Kensington, London
Posts: 778
Create table A
(
id Integer IDENTITY(1, 1),
name varchar(10),
Constraint A_PK primary key(id)
)

Create table B
(
id Integer,
name varchar(10),
Constraint B_FK_ID foreign key (id) references a(id)
)
__________________
Bessie Braddock: Winston, you are drunk!
Churchill: And Madam, you are ugly. And tomorrow, I'll be sober, and you will still be ugly.
Reply With Quote
  #3 (permalink)  
Old 02-18-04, 05:12
andrewst andrewst is offline
Moderator.
 
Join Date: Sep 2002
Location: UK
Posts: 5,171
Quote:
Originally posted by r123456
Create table A
(
id Integer IDENTITY(1, 1),
name varchar(10),
Constraint A_PK primary key(id)
)

Create table B
(
id Integer,
name varchar(10),
Constraint B_FK_ID foreign key (id) references a(id)
)
Yes, but I think Alex meant: how do you find out the value of A.ID just inserted when you go on to insert into B?

insert into A (name) values ('smith');
insert into B (id, name) values (?????, 'jones');

Presumably these DBMSs have a "get_last_identity_used" function or something? Or do they support a RETURNING clause on insert like Oracle does? :-

insert into A (name) values ('smith') returning id into v_id;
insert into B (id, name) values (v_id, 'jones');
__________________
Tony Andrews
http://tinyurl.com/tonyandrews
Reply With Quote
  #4 (permalink)  
Old 02-18-04, 07:40
r123456 r123456 is offline
Registered User
 
Join Date: Sep 2003
Location: The extremely Royal borough of Kensington, London
Posts: 778
The last Identity value can be obtained in SQL Server 2000 by calling @@identity.
Code:
Insert into a values (D)
Insert into a values (E) 
Select * from a where id > 3;

ID   VAR
---  ------
 4      D
 5      E

Select @@identity
= 6
__________________
Bessie Braddock: Winston, you are drunk!
Churchill: And Madam, you are ugly. And tomorrow, I'll be sober, and you will still be ugly.
Reply With Quote
  #5 (permalink)  
Old 02-18-04, 09:28
akoyfman akoyfman is offline
Registered User
 
Join Date: Feb 2004
Location: USA (East Coast)
Posts: 6
Question

What is the scope of @@identity variable - global, user session? Is it safe to use this in multi-user environment? I believe it is.

But this is SQL Server... I am looking for one cross-database uniform way of doing this.

First scenario works for Oracle and DB2 (sequence object):

1. Obtain new unique id.
2. Insert new record into primary table using obtained id as a primary key.
3. Insert records into dependent tables using obtained id as a foreign key.

Second scenario works for SQL Server (select @@identity):

1. Insert new record into primary table.
2. Obtain primary key value of just inserted record.
3. Insert records into dependent tables using obtained primary key value as a foreign key.

I am not sure what scenarios are for MS Access, MySQL, and other databases. Is there a universal way of doing this?

-Alex
Reply With Quote
  #6 (permalink)  
Old 02-18-04, 10:12
andrewst andrewst is offline
Moderator.
 
Join Date: Sep 2002
Location: UK
Posts: 5,171
No, there is no standard way that applies across the various DBMSs. Best to encapsulate your (insert row and get generated PK) logic inside a procedure which can then be re-implemented for each DBMS. Preferably a stored procedure, if all your DBMSs support them.
__________________
Tony Andrews
http://tinyurl.com/tonyandrews
Reply With Quote
  #7 (permalink)  
Old 02-18-04, 12:05
akoyfman akoyfman is offline
Registered User
 
Join Date: Feb 2004
Location: USA (East Coast)
Posts: 6
Unhappy

That's a shame. What I am trying to do is very common task. It should be standardized across databases.

For my purpose I will use sequence object if database provides it, and simulate sequence if database does not provide it. For example, I can create SEQUENCES table with SEQUENCE_NAME (unique), and SEQUENCE_VALUE, and have a procedure that controls this table and returns next value for specified name. This should work universally.

Thank you for your help.

Alex
Reply With Quote
  #8 (permalink)  
Old 02-18-04, 12:24
andrewst andrewst is offline
Moderator.
 
Join Date: Sep 2002
Location: UK
Posts: 5,171
Universally, but not very scalably perhaps. Presumably the SEQUENCES row for the SEQUENCE_NAME will be updated in the same transaction that is performing the insert - in which case, no one else can insert into the same table until the current user commits.

Idea: how about having a dummy table with an autogenerated ID column instead of the SEQUENCES table? The the get_next_id procedure would be something like:

begin
insert into dummy table (dummy) values ('x');
select @@identity;
end
__________________
Tony Andrews
http://tinyurl.com/tonyandrews
Reply With Quote
  #9 (permalink)  
Old 02-18-04, 12:42
akoyfman akoyfman is offline
Registered User
 
Join Date: Feb 2004
Location: USA (East Coast)
Posts: 6
But what is the difference between your way and my way in terms of scalability? Why does my 'get next value' create a bottleneck if executed within one transaction but yours does not? You just changed the algorithm of generating the key - used insert instead of update. Or I am missing something.

-Alex
Reply With Quote
  #10 (permalink)  
Old 02-18-04, 12:47
andrewst andrewst is offline
Moderator.
 
Join Date: Sep 2002
Location: UK
Posts: 5,171
What you are missing is that the insert into a dummy table does not lock anything, so n>1 users can call it concurrently. The provision of the autoincrement value by the DBMS does not form part of the transaction (I sincerely hope and believe!)
__________________
Tony Andrews
http://tinyurl.com/tonyandrews
Reply With Quote
  #11 (permalink)  
Old 02-18-04, 12:52
r937 r937 is offline
SQL Consultant
 
Join Date: Apr 2002
Location: Toronto, Canada
Posts: 19,524
Quote:
Originally posted by andrewst
No, there is no standard way that applies across the various DBMSs.
actually, there is

it comes from the realization that the autonumber or sequence or identity is a surrogate key, and there is some other candidate key in the table that also provides uniqueness, even if this consists of all the other columns in the table

(and as an aside, if there is no other column or set of columns that are unique, then you have a deficient design -- but that's a completely nuther thread)

so, do your isert, but hold on to the values of all the candidate key columns

then, just query the row back using those values

for example, let's say the employee table has an identity field for the employee number --
PHP Code:
insert 
  into employees 
     
fname
     
lname
     
email
     
dob
     
)
values 
     
'Joe'
     
'Example'
     
'joe@example.com'
     
'1971-03-04'
     
)

select employeeno 
  from employees
 where fname 
'Joe'
   
and lname 'Example'
   
and email 'joe@example.com'
   
and dob   '1971-03-04' 
some people will see this and say "eewww, an extra SELECT step" but i would like to point out that

1. it works in all DBMSs, and

2. it does not require any locking or a transaction block, i.e. it does not matter how many other employees were added to the table in between my INSERT and SELECT
__________________
r937.com | rudy.ca
please visit Simply SQL and buy my book
Reply With Quote
  #12 (permalink)  
Old 02-18-04, 13:00
andrewst andrewst is offline
Moderator.
 
Join Date: Sep 2002
Location: UK
Posts: 5,171
Quote:
Originally posted by r937
actually, there is
...
Good point! And the fact that it almost forces you to define a "proper" unique key can only be good!
__________________
Tony Andrews
http://tinyurl.com/tonyandrews
Reply With Quote
  #13 (permalink)  
Old 02-19-04, 19:43
byrmol byrmol is offline
Registered User
 
Join Date: Mar 2003
Location: Australia
Posts: 59
Bravo, r937!
Reply With Quote
  #14 (permalink)  
Old 02-20-04, 15:15
mr_java66 mr_java66 is offline
Registered User
 
Join Date: Feb 2004
Posts: 2
Quote:
Originally posted by andrewst
Universally, but not very scalably perhaps. Presumably the SEQUENCES row for the SEQUENCE_NAME will be updated in the same transaction that is performing the insert - in which case, no one else can insert into the same table until the current user commits.

Idea: how about having a dummy table with an autogenerated ID column instead of the SEQUENCES table? The the get_next_id procedure would be something like:

begin
insert into dummy table (dummy) values ('x');
select @@identity;
end
fyi
@@identity is not thread safe, scope_identity() is much better.
Reply With Quote
Reply

Thread Tools Search this Thread
Search this Thread:

Advanced Search
Display Modes

Posting Rules
You may not post new threads
You may not post replies
You may not post attachments
You may not edit your posts

BB code is On
Smilies are On
[IMG] code is Off
HTML code is Off
Trackbacks are On
Pingbacks are On
Refbacks are On