I have a set of tables that's actually a stubby tree. At the top, there's a Customer, and below that Invoices, and Invoice Detail records. (In actuality, there's about two dozen of these tables all referring to the Customer but the principle should apply with just three tables.)
What I'd like to do is to copy the Customer and all of the records belonging to that Customer without having to enumerate every single field in every record. Everything is foreign-key constrained to the thing above it, and most of the tables have auto-increment identity fields.
Below is a T-SQL script to set up a database. Yes it's messy, but it's complete.
CREATE TABLE [dbo].[Customer](
[custID] [int] IDENTITY(1,1) NOT NULL,
[name] [varchar](50) NOT NULL,
CONSTRAINT [PK_Customer] PRIMARY KEY CLUSTERED ( [custID] ASC)
WITH (PAD_INDEX = OFF, STATISTICS_NORECOMPUTE = OFF, IGNORE_DUP_KEY = OFF,
ALLOW_ROW_LOCKS = ON, ALLOW_PAGE_LOCKS = ON) ON [PRIMARY] ) ON [PRIMARY]
GO
CREATE TABLE [dbo].[Invoice](
[invoiceNum] [int] IDENTITY(1,1) NOT NULL,
[custID] [int] NOT NULL,
[Description] [varchar](50) NOT NULL,
CONSTRAINT [PK_Invoice] PRIMARY KEY CLUSTERED ( [invoiceNum] ASC )
WITH (PAD_INDEX = OFF, STATISTICS_NORECOMPUTE = OFF, IGNORE_DUP_KEY = OFF,
ALLOW_ROW_LOCKS = ON, ALLOW_PAGE_LOCKS = ON) ON [PRIMARY] ) ON [PRIMARY]
GO
CREATE TABLE [dbo].[InvoiceDetail](
[invoiceNum] [int] NOT NULL,
[sequence] [smallint] NOT NULL,
[description] [varchar](50) NOT NULL,
[price] [decimal](10, 2) NOT NULL CONSTRAINT [DF_InvoiceDetail_price] DEFAULT ((0.0)),
CONSTRAINT [PK_InvoiceDetail] PRIMARY KEY CLUSTERED ( [invoiceNum] ASC, [sequence] ASC )
WITH (PAD_INDEX = OFF, STATISTICS_NORECOMPUTE = OFF, IGNORE_DUP_KEY = OFF,
ALLOW_ROW_LOCKS = ON, ALLOW_PAGE_LOCKS = ON) ON [PRIMARY] ) ON [PRIMARY]
GO
ALTER TABLE [dbo].[Invoice] WITH CHECK ADD CONSTRAINT [FK_Invoice_Customer]
FOREIGN KEY([custID])
REFERENCES [dbo].[Customer] ([custID])
GO
ALTER TABLE [dbo].[Invoice] CHECK CONSTRAINT [FK_Invoice_Customer]
GO
ALTER TABLE [dbo].[InvoiceDetail] WITH CHECK ADD CONSTRAINT [FK_InvoiceDetail_Invoice]
FOREIGN KEY([invoiceNum])
REFERENCES [dbo].[Invoice] ([invoiceNum])
GO
ALTER TABLE [dbo].[InvoiceDetail] CHECK CONSTRAINT [FK_InvoiceDetail_Invoice]
declare @id int;
declare @custid int;
insert into Customer values ('Bob');
set @custid = @@IDENTITY;
insert into Invoice values ( @custid, 'Little Purchase');
set @id = @@IDENTITY;
insert into InvoiceDetail values (@id, 1, 'Small Stuff', 1.98);
insert into InvoiceDetail values (@id, 2, 'More Small Stuff', 0.25);
insert into Invoice values ( @custid, 'Medium Purchase');
set @id = @@IDENTITY;
insert into InvoiceDetail values (@id, 1, 'Stuff', 11.95);
insert into InvoiceDetail values (@id, 2, 'More Stuff', 10.66);
insert into Customer values ('Sally');
set @custid = @@IDENTITY;
insert into Invoice values ( @custid, 'Big Purchase');
set @id = @@IDENTITY;
insert into InvoiceDetail values (@id, 1, 'BIG Stuff', 100.00);
insert into InvoiceDetail values (@id, 2, 'Larger Stuff', 99.95);
So what I want to do is make a copy of "Bob" in this database, and call it "Bob2" without all of the hassle of specifying each column for every table. I could, but in the Real World that's a LOT of columns.
The other problem being that I'd have to write an explicit loop to get each of the invoices. I need the identity from the previous Invoice insert in order to write the Invoice Detail.
I've got a working C# "copy" program, but I'd like to do this all in the database. The naive implementation is a transact sql stored procedure with loops and cursors everywhere.
Is there a clever way of avoiding one (if not both) of these issues?