J'ai un ensemble de tables qui est en fait un arbre tronqué. En haut, il y a un client, et en dessous de ces factures, et des enregistrements de détails de facture. (En réalité, il y a environ deux douzaines de ces tables faisant toutes référence au Client mais le principe ne devrait s'appliquer qu'à trois tables.)Copie d'un ensemble d'enregistrements avec des contraintes, avec un ancêtre commun
Ce que j'aimerais faire, c'est copier le Client et tous les enregistrements appartenant à ce client sans avoir à énumérer chaque champ dans chaque enregistrement. Tout est étranger-clé contraint à la chose au-dessus de lui, et la plupart des tables ont des champs d'identité d'auto-incrémentation.
Vous trouverez ci-dessous un script T-SQL pour configurer une base de données. Oui, c'est en désordre, mais c'est complet.
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);
Donc ce que je veux faire est de faire une copie de « Bob » dans cette base de données, et l'appeler « BOB2 » sans tous les tracas de spécifier chaque colonne pour chaque table. Je pourrais, mais dans le monde réel c'est beaucoup de colonnes. L'autre problème étant que je devrais écrire une boucle explicite pour obtenir chacune des factures. J'ai besoin de l'identité de l'insertion de facture précédente pour écrire le détail de facture.
J'ai un programme de copie en C#, mais j'aimerais le faire dans la base de données. L'implémentation naïve est une procédure stockée sql transact avec des boucles et des curseurs partout.
Y a-t-il un astucieux pour éviter l'un de ces problèmes (si ce n'est les deux)?
Il n'y a pas vraiment de "Clients" et de "Factures". Il serait inapproprié d'afficher un schéma réel dans un forum public. Ils imitent une vraie base de données cependant. –