I need to get data in two parent> sets of child tables, merged / merged into a third parent> child table.
The tables look like this:

The only difference in the three sets of tables is that TableC has a TableType column to recognize the difference between the TableA record and the TableB record.
My first thought was to use a cursor. Here's the code to create the table structure, insert some records, and then combine the data together. It works very well, sooooo ....
--Create the tables CREATE TABLE TableA ( ID int not null identity primary key, Name VARCHAR(30) ); CREATE TABLE TableAChild ( ID int not null identity primary key, Parent int not null, Name VARCHAR(30), CONSTRAINT FK_A FOREIGN KEY (Parent) REFERENCES TableA(ID) ); CREATE TABLE TableB ( ID int not null identity primary key, Name VARCHAR(30) ); CREATE TABLE TableBChild ( ID int not null identity primary key, Parent int not null, Name VARCHAR(30), CONSTRAINT FK_B FOREIGN KEY (Parent) REFERENCES TableB(ID) ); CREATE TABLE TableC ( ID int not null identity primary key, TableType VARCHAR(1), Name VARCHAR(30) ); CREATE TABLE TableCChild ( ID int not null identity primary key, Parent int not null, Name VARCHAR(30), CONSTRAINT FK_C FOREIGN KEY (Parent) REFERENCES TableC(ID) ); -- Insert some test records.. INSERT INTO TableA (Name) Values ('A1') INSERT INTO TableAChild (Name, Parent) VALUES ('A1Child', SCOPE_IDENTITY()) INSERT INTO TableB (Name) Values ('B1') INSERT INTO TableBChild (Name, Parent) VALUES ('B1Child', SCOPE_IDENTITY()) -- Needed throughout.. DECLARE @ID INT -- Merge TableA and TableAChild into TableC and TableCChild DECLARE TableACursor CURSOR -- Get the primary key from TableA FOR SELECT ID FROM TableA OPEN TableACursor FETCH NEXT FROM TableACursor INTO @ID WHILE @@FETCH_STATUS = 0 BEGIN -- INSERT INTO SELECT the parent record into TableC, being sure to specify a TableType INSERT INTO TableC (Name, TableType) SELECT Name, 'A' FROM TableA WHERE ID = @ID -- INSERT INTO SELECT the child record into TableCChild using the parent ID of the last row inserted (SCOPE_IDENTITY()) -- and the current record from the cursor (@ID). INSERT INTO TableCChild(Name, Parent) SELECT Name, SCOPE_IDENTITY() FROM TableAChild WHERE Parent = @ID FETCH NEXT FROM TableACursor INTO @ID END; CLOSE TableACursor DEALLOCATE TableACursor -- Repeat for TableB DECLARE TableBCursor CURSOR FOR SELECT ID FROM TableB OPEN TableBCursor FETCH NEXT FROM TableBCursor INTO @ID WHILE @@FETCH_STATUS = 0 BEGIN INSERT INTO TableC (Name, TableType) SELECT Name, 'B' FROM TableB WHERE ID = @ID INSERT INTO TableCChild(Name, Parent) SELECT Name, SCOPE_IDENTITY() FROM TableBChild WHERE Parent = @ID FETCH NEXT FROM TableBCursor INTO @ID END; CLOSE TableBCursor DEALLOCATE TableBCursor
Now, my question (s):
- I've always been told that cursors are bad. But I could not find another way to do this. I am wondering if there is a way to do this using CTE?
- If the cursor is suitable in this situation, how did I do it? Is there a better way to do what I did? This does not look very dry for me, but I am not an SQL expert.
Finally, if you want to rerun the query above, here is a small script to delete the created tables.
DROP TABLE TableAChild DROP TABLE TableBChild DROP TABLE TableCChild DROP TABLE TableA DROP TABLE TableB DROP TABLE TableC
The correct result should look like this:

sql sql-server common-table-expression cursor
Alex dresko
source share