views:

441

answers:

2

I have two tables, the first has a primary key that is an identity, the second has a primary key that is not, but that key has a foreign key constraint back to the first table's primary key.

If I am inserting one record at a time I can use the Scope_Identity to get the value for the pk just inserted in table 1 that I want to insert into the second table.

My problem is I have many records coming from selects I want to insert in both tables, I've not been able to think of a set based way to do these inserts.

My current solution is to use a cursor, insert in the first table, get key using scope_identity, insert into second table, repeat.

Am I missing a non-cursor solution?

+2  A: 

Yes, Look up the output clause in Books online.

HLGEM
This looks promising, but an issue/question. Seems there would need to be enough information supplied by the output clause to uniquely match the output rows back to the correct rows in the input select so that I can use the scope_identity values. This may not always be available.
automatic
You could always return all columns, if that isn't unique it probably should be.If you can't make it unique, you could add another column for the table for the temp id, putting the data to be inserted into a temp table with an identity and insert that, then grab that and the real identifier with the output clause and immediately null out the temp id values. That could work if you don't have a concurrency issue. With a concurrency issue, you could try the same thing only using GUIDS as the temp id and then be sure only to null out those records that match a GUID in your temp table.
HLGEM
A: 

I had this problem just this week: someone had introduced a table with a meaningless surrogate key into the schema where naturally keys are used. No doubt I'll fix this soon :) until then, I'm working around it by creating a table of data to INSERT from: this could be a permanent or temporary base table or a derived table (see below), which should suit your desire for a set-based solution anyhow. Use a join between this table and the table with the IDENTITY column on the natural key to find out the auto-generated values. Here's a brief example:

CREATE TABLE Test1 
(
 surrogate_key INTEGER IDENTITY NOT NULL UNIQUE, 
 natural_key CHAR(10) NOT NULL CHECK (natural_key NOT LIKE '%[^0-9]%') UNIQUE
);

CREATE TABLE Test2
(
 surrogate_key INTEGER NOT NULL UNIQUE
    REFERENCES Test1 (surrogate_key), 
 data_col INTEGER NOT NULL
);

INSERT INTO Test1 (natural_key)
SELECT DT1.natural_key
  FROM (
        SELECT '0000000001', 22
        UNION ALL 
        SELECT '0000000002', 55
        UNION ALL 
        SELECT '0000000003', 99
       ) AS DT1 (natural_key, data_col);

INSERT INTO Test2 (surrogate_key, data_col)
SELECT T1.surrogate_key, DT1.natural_key
  FROM (
        SELECT '0000000001', 22
        UNION ALL 
        SELECT '0000000002', 55
        UNION ALL 
        SELECT '0000000003', 99
       ) AS DT1 (natural_key, data_col)
       INNER JOIN Test1 AS T1
          ON T1.natural_key = DT1.natural_key;
onedaywhen