Example user-defined table type for use as a table-valued parameter:
create type dbo.InvoiceItems_udt as table (
ProductId int
, Quantity decimal(9,2)
, LineTotal decimal(19,2)
);
go
Example procedure using
scope_identity()
to get the
InvoiceId
after inserting a row into
dbo.Invoice
:
create procedure dbo.Invoice_Insert_WithItems (
@InvoiceId int output
, @CustomerId int not null
, @InvoiceItems dbo.InvoiceItems_udt readonly
) as
begin;
set nocount on, xact_abort on;
begin tran;
insert into dbo.Invoice (CustomerId, InvoiceTotal)
select @CustomerId, InvoiceTotal = sum(LineTotal)
from @InvoiceItems i;
select @InvoiceId = scope_identity();
insert into dbo.InvoiceItems (InvoiceId, ProductId, Quantity, LineTotal)
select @InvoiceId, ProductId, Quantity, LineTotal
from @InvoiceItems i;
commit tran;
end;
go
In SQL Server 2012+, an alternative to using an auto-numbered
identity()
for
InvoiceId,
you could use a
sequence
.
Example of how to create and use a sequence
as the primary key on dbo.Invoice
:
create sequence dbo.InvoiceIdSequence as int
start with 1
increment by 1;
create table dbo.Invoice (
InvoiceId int not null default next value for dbo.InvoiceIdSequence
, CustomerId int not null
, InvoiceTotal decimal(19,2)
, constraint pk_Invoice primary key clustered (InvoiceId)
, constraint fk_Invoice_Customer foreign key (CustomerId)
references dbo.Customer(CustomerId)
);
In this example, instead of using
scope_identity()
after inserting a row into
dbo.Invoice
, we would use
next value for
dbo.InvoiceIdSequence
before inserting a row into
dbo.Invoice
.
create procedure dbo.Invoice_Insert_WithItems (
@InvoiceId int output
, @CustomerId int not null
, @InvoiceItems dbo.InvoiceItems_udt readonly
) as
begin;
set nocount on, xact_abort on;
begin tran;
set @InvoiceId = next value for dbo.InvoiceIdSequence;
insert into dbo.Invoice (CustomerId, InvoiceId, InvoiceTotal)
select @CustomerId, @InvoiceId, InvoiceTotal = sum(LineTotal)
from @InvoiceItems i;
insert into dbo.InvoiceItems (InvoiceId, ProductId, Quantity, LineTotal)
select @InvoiceId, ProductId, Quantity, LineTotal
from @InvoiceItems i;
commit tran;
end;
go
private static void ExecuteProcedure(bool useDataTable, string connectionString, IEnumerable<long> ids) {
using (SqlConnection connection = new SqlConnection(connectionString)) {
connection.Open();
using (SqlCommand command = connection.CreateCommand()) {
command.CommandText = "dbo.procMergePageView";
command.CommandType = CommandType.StoredProcedure;
SqlParameter parameter;
if (useDataTable) {
parameter = command.Parameters.AddWithValue("@Display", CreateDataTable(ids));
}
else {
parameter = command.Parameters.AddWithValue("@Display", CreateSqlDataRecords(ids));
}
parameter.SqlDbType = SqlDbType.Structured;
parameter.TypeName = "dbo.PageViewTableType";
command.ExecuteNonQuery();
}
}
}
private static DataTable CreateDataTable(IEnumerable<long> ids) {
DataTable table = new DataTable();
table.Columns.Add("ID", typeof(long));
table.Columns.Add("Name", typeof(string));
foreach (long id in ids) {
table.Rows.Add(id);
table.Rows.Add("subrat");
}
return table;
}
private static IEnumerable<SqlDataRecord> CreateSqlDataRecords(IEnumerable<long> ids) {
SqlMetaData[] metaData = new SqlMetaData[2];
metaData[0] = new SqlMetaData("ID", SqlDbType.BigInt);
metaData[1] = new SqlMetaData("Name", SqlDbType.NVar,100);
SqlDataRecord record = new SqlDataRecord(metaData);
foreach (long id in ids) {
record.SetInt64(0, id);
record.SetString(1, "subrat");
yield return record;
}
}