I have accepted @SqlZim’s answer, but felt that the following simplified example, based on his or her answer, might be helpful.
First some sample tables.
create table invoices(
id int identity(1,1) primary key nonclustered,
customerid int, -- references customers(id)
date date,
total decimal(7,3)
);
create table invoiceitems(
id int identity(1,1) primary key nonclustered,
invoiceid int references invoices(id),
productid int, -- references products(id)
quantity int,
price decimal(5,3)
);
create type invoice as table(
productid int,
quantity int,
price decimal(5,3)
);
In principal, the tables contain some foreign keys which are commented out for simplicity. However, there is one important foreign key: invoiceid int references invoices(id)
.
A procedure would work as follows:
create procedure addInvoice (
@customerid int,
@items invoice readonly,
@id int=null output
) as
begin
declare @total decimal(7,3);
begin transaction;
insert into invoices(customerid) values(@customerid);
set @id=scope_identity();
insert into invoiceitems(invoiceid,productid,quantity,price)
select @id,productid,quantity,price from @items;
set @total=(select sum(quantity*price) from @items);
update invoices set total=@total where id=@id;
commit transaction;
end;
In this case there is also a field in the parent table which is updated after the child records are added.
There is an optional return parameter, just in case you want to use the newly created primary key of the parent.
To execute the procedure:
declare @items invoice;
INSERT INTO @items(productid,quantity,price)
values
(13,3,16),
(14,1,12),
(19,4,8),
(11,2,17);
execute addInvoice 42,@items;
This example ignores the return value. If you need it:
declare @id int;
execute addInvoice 42,@items,@id=@id output;
select @id;
@SqlZim’s answer is, of course, more comprehensive. Thanks.
exec addInvoice(…);
or whatever is the correct syntax for calling a procedure.