如何编写SQL查询以从多对多关系插入到多对多关系?

时间:2011-11-18 21:54:38

标签: sql sql-server sql-server-2008 many-to-many sql-server-2008-r2

我有以下两个表/列:

TableA
id | data

TableB
fkeyA1 | fkeyA2 | fkeyA3 | name

TableB中的前三列是所有指向TableA的外键。我想将TableB转换为以下两个表:

TableC
id | name

TableD
fkeyC | fkeyA

使TableB中的一行成为TableC中的一行加上TableD中的三行。我该如何为此编写SQL查询?

编辑:

TableB中,(fkeyA1, fkeyA2, fkeyA3)上有一个唯一索引,但name列不一定具有唯一值。

2 个答案:

答案 0 :(得分:1)

我首先要插入到tableC中,IdIDENTITY

INSERT INTO TableC(name)
SELECT b.name
FROM TableB AS b

然后我会写一个插入内容:

SELECT c.Id, b.fkeyA1
FROM TableC AS c
INNER JOIN tableB AS b ON c.name = b.name
UNION    
SELECT c.Id, b.fkeyA2
FROM TableC AS c
INNER JOIN tableB AS b ON c.name = b.name
UNION
SELECT c.Id, b.fkeyA3
FROM TableC AS c
INNER JOIN tableB AS b ON c.name = b.name

INSERT进入TableD的另一种方法是:

SELECT c.Id, a.Id
FROM TableB AS b
INNER JOIN TableC AS c ON b.name = c.name
LEFT JOIN TableA AS a ON b.fkeyA1 = a.Id
   OR b.fkeyA2 = a.Id
   OR b.fkeyA3 = a.Id

如果tableB包含名称“Adam”两次,则B中的两个记录将由TableC中的相同Id引用,TableD将具有该Id的6个记录

例如

TableA         TableB                   TableC          TableD
1, 'Data1'     1, 2, 3, 'Adam'          1, 'Adam'       1, 1
2, 'Data2'     4, 5, 6, 'Someone'       2, 'Someone'    1, 2
3, 'Data3'     7, 8, 9, 'Adam'                          1, 3
4, 'Data4'                                              1, 7
5, 'Data5'                                              1, 8
6, 'Data6'                                              1, 9
7, 'Data7'                                              2, 4
8, 'Data8'                                              2, 5
9, 'Data9'                                              2, 6

答案 1 :(得分:1)

您可以使用游标语句:

declare @idC table(id int)
declare @fkeyC int, @fkeyA1 int, @fkeyA2 int, @fkeyA3 int, @name varchar(8)
declare CursorB cursor fast_forward for select fkeyA1, fkeyA2, fkeyA3, name from TableB
open CursorB
fetch next from CursorB into @fkeyA1, @fkeyA2, @fkeyA3, @name
while @@fetch_status = 0
begin
    insert into TableC(name) output inserted.id into @idC values (@name)
    set @fkeyC = (select top 1 id from @idC)
    insert into TableD(fkeyC, fkeyA) values (@fkeyC, @fkeyA1), (@fkeyC, @fkeyA2), (@fkeyC, @fkeyA3)
    delete from @idC
    fetch next from CursorB into @fkeyA1, @fkeyA2, @fkeyA3, @name
end
close CursorB
deallocate CursorB

这可能不是性能最好的,但会允许名称列的非唯一值。