我需要在两个父母>中获取数据子表集合并/组合成第三父表格>儿童表。
表格如下:
三组表的唯一区别是TableC有一个TableType
列,可帮助识别TableA记录和TableB记录之间的差异。
我的第一个想法是使用游标..这是创建表结构,插入一些记录,然后将数据合并在一起的代码。它工作得非常好,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
现在,我的问题:
最后,如果你想重新运行上面的查询,这里有一个小脚本来删除创建的表。
DROP TABLE TableAChild
DROP TABLE TableBChild
DROP TABLE TableCChild
DROP TABLE TableA
DROP TABLE TableB
DROP TABLE TableC
正确的结果应如下所示:
答案 0 :(得分:4)
您可以在merge和Dr. OUTPUT or: How I Learned to Stop Worrying and Love the MERGE问题中使用Adam Machanic所述的this来获取表格变量中新标识值和旧主键值之间的映射关系插入子表时的用法。
declare @T table(ID int, IDC int);
merge dbo.TableC as C
using dbo.TableA as A
on 0 = 1
when not matched by target then
insert (TableType, Name) values('A', A.Name)
output A.ID, inserted.ID into @T(ID, IDC);
insert into dbo.TableCChild(Parent, Name)
select T.IDC, AC.Name
from dbo.TableAChild as AC
inner join @T as T
on AC.Parent = T.ID;
delete from @T;
merge dbo.TableC as C
using dbo.TableB as B
on 0 = 1
when not matched by target then
insert (TableType, Name) values('B', B.Name)
output B.ID, inserted.ID into @T(ID, IDC);
insert into dbo.TableCChild(Parent, Name)
select T.IDC, BC.Name
from dbo.TableBChild as BC
inner join @T as T
on BC.Parent = T.ID;
答案 1 :(得分:1)
这是一种没有光标或其他RBAR类型的方法。
ALTER TABLE TableC ADD LegacyID INT
GO
INSERT INTO TableC (TableType, Name, LegacyID)
SELECT 'A', Name, ID
FROM TableA
INSERT TableCChild
SELECT C.ID, AC.Name
FROM TableAChild AC
JOIN TableA A ON A.Id = AC.ID
JOIN TableC C ON C.LegacyID = A.ID AND C.TableType = 'A'
INSERT INTO TableC (TableType, Name, LegacyID)
SELECT 'B', Name, ID
FROM TableB
INSERT TableCChild
SELECT C.ID, AC.Name
FROM TableBChild AC
JOIN TableB A ON A.Id = AC.ID
JOIN TableC C ON C.LegacyID = A.ID AND C.TableType = 'B'
ALTER TABLE TableC DROP COLUMN LegacyID
GO
答案 2 :(得分:0)
您可以使用map
表根据某些键将旧ID和新ID链接在一起。
在我的示例中,我使用的是TableC
的插入顺序。
TableC
ID
的顺序在TableA
表中添加数据,并在地图中插入ID TableA.id
的相同顺序获取ROWNUMBER()
并将其与地图表的标识列相匹配,并更新地图中的old_id
以匹配TableA.id
TableC.id
。TableCChild
表格示例查询
CREATE TABLE #map(id int identity,new_id int,old_id int);
INSERT INTO TableC
(
TableType,
Name
)output inserted.id into #map(new_id)
SELECT 'A',Name
FROM TableA
ORDER BY ID
update m
set m.old_id = ta.id
FROM #map m
inner join
(
select row_number()OVER(order by id asc) rn,id
from tableA
)ta on ta.rn = m.id
INSERT INTO TableCChild (Name, Parent)
SELECT Name,M.new_ID
FROM #Map M
INNER JOIN TableAChild TA ON M.old_id = TA.Parent
TRUNCATE TABLE #map
INSERT INTO TableC
(
TableType,
Name
)output inserted.id into #map(new_id)
SELECT 'B',Name
FROM TableB
ORDER BY ID
update m
set m.old_id = tb.id
FROM #map m
inner join
(
select row_number()OVER(order by id asc) rn,id
from tableB
)tb on tb.rn = m.id
INSERT INTO TableCChild (Name, Parent)
SELECT Name,M.new_ID
FROM #Map M
INNER JOIN TableBChild TB ON M.old_id = TB.Parent
DROP TABLE #Map
答案 3 :(得分:0)
如果Name在TableA中是唯一的并且在TableB中是唯一的,那么我只是编写了以下SQL来执行此操作
INSERT INTO TableCChild
(
Parent,
NAME
)
SELECT tc.ID,
ta.Name
FROM TableAChild AS ta
JOIN TableA a
ON a.ID = ta.Parent
JOIN TableC AS tc
ON tc.Name = a.Name
AND tc.TableType = 'A'
UNION
SELECT tc.ID,
tb.Name
FROM TableBChild AS tb
JOIN TableB b
ON b.ID = tb.Parent
JOIN TableC AS tc
ON tc.Name = b.Name
AND tc.TableType = 'B'
如果Name不是唯一的,只有ID是唯一标识符,那么我会按照建议添加LegacyId,然后代码如下
/* Change Table C to Have LegacyId as well and this is used to find the New Key for Inserts
CREATE TABLE TableC
(
ID INT NOT NULL IDENTITY PRIMARY KEY,
TableType VARCHAR(1),
LegacyId INT,
NAME VARCHAR(30)
);
*/
INSERT INTO TableC (Name, TableType, LegacyId)
SELECT DISTINCT NAME,
'A',
Id
FROM TableA
UNION
SELECT DISTINCT NAME,
'B',
Id
FROM TableB
INSERT INTO TableCChild
(
Parent,
NAME
)
SELECT tc.ID,
ta.Name
FROM TableAChild AS ta
JOIN TableA a
ON a.ID = ta.Parent
JOIN TableC AS tc
ON tc.LegacyId = a.Id
AND tc.TableType = 'A'
UNION
SELECT tc.ID,
tb.Name
FROM TableBChild AS tb
JOIN TableB b
ON b.ID = tb.Parent
JOIN TableC AS tc
ON tc.LegacyId = b.Id
AND tc.TableType = 'B'
答案 4 :(得分:0)
我们可以通过关闭标识列直到我们完成插入来达到此目的。如下例所示。
--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())
SET IDENTITY_INSERT TableC ON
INSERT INTO TableC(ID, TableType, Name)
SELECT ID, 'A', Name FROM TableA
INSERT INTO TableCChild(Parent, Name)
SELECT Parent, Name FROM TableAChild
DECLARE @MAXID INT
SELECT @MAXID = MAX(ID) FROM TableC
PRINT @MAXID
SET IDENTITY_INSERT TableC ON
INSERT INTO TableC(ID, TableType, Name)
SELECT ID + @MAXID, 'B', Name FROM TableB
SET IDENTITY_INSERT TableC OFF
INSERT INTO TableCChild(Parent, Name)
SELECT Parent + @MAXID, Name FROM TableBChild
SET IDENTITY_INSERT TableC OFF
SELECT * FROM TableC
SELECT * FROM TableCChild
DROP TABLE TableAChild
DROP TABLE TableBChild
DROP TABLE TableCChild
DROP TABLE TableA
DROP TABLE TableB
DROP TABLE TableC
答案 5 :(得分:0)
如果您需要在第三个表TableC和TableCChild中插入记录供以后使用,那么可以在这些表中插入数据,但如果您只需要此表数据暂时在存储过程中使用它那么你也可以使用前两个表来获得所需的结果。
select * from (
select a.ID,'A' as TableType,a.Name from TableA a inner join TableAChild b on a.ID=b.ID
union
select a.ID,'B' as TableType,a.Name from TableB a inner join TableBChild b on a.ID=b.ID) TableC
同样获取TableCChild
select * from
(
select b.ID,b.Parent,b.Name from TableA a inner join TableAChild b on a.ID=b.ID
union
select b.ID,b.Parent,b.Name from TableB a inner join TableBChild b on a.ID=b.ID) TableCChild
如果必须在TableC和TableCChild中插入,则必须使用ID和TableType上的主键重新创建TableC,并关闭ID列的标识。