如何编写SQL查询以将三重多对一关系插入到多对多关系?
I以下两个表/列:如何编写SQL查询以将三重多对一关系插入到多对多关系?,sql,sql-server,sql-server-2008,many-to-many,sql-server-2008-r2,Sql,Sql Server,Sql Server 2008,Many To Many,Sql Server 2008 R2,I以下两个表/列: TableA id | data TableB fkeyA1 | fkeyA2 | fkeyA3 | name TableB中的前三列是外键,都指向TableA。我想将表B转换为以下两个表: TableC id | name TableD fkeyC | fkeyA 所以表B中的一行变成表C中的一行加上表D中的三行。我应该如何为此编写SQL查询 编辑: 在表格B中,在(fkeyA1,fkeyA2,fkeyA3)上有一个唯一的索引,但是名称列不一定有唯一的值。我首先在表
TableA
id | data
TableB
fkeyA1 | fkeyA2 | fkeyA3 | name
TableB中的前三列是外键,都指向TableA。我想将表B转换为以下两个表:
TableC
id | name
TableD
fkeyC | fkeyA
所以表B中的一行变成表C中的一行加上表D中的三行。我应该如何为此编写SQL查询
编辑:
在
表格B
中,在(fkeyA1,fkeyA2,fkeyA3)
上有一个唯一的索引,但是名称
列不一定有唯一的值。我首先在表格C中插入Id
作为标识的列
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
插入表格的另一种方法是:
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将有6条该Id的记录
例如
您可以使用游标语句:
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
这可能不是性能最好的,但会允许名称列的值不唯一。从逻辑上讲,我认为不需要嵌套COALESCE()
——不管怎样,我认为您的意思是在b.fkeyA1=a.Id或b.fkeyA2=a.Id或b.fkeyA3=a.Id上以a的形式左联接表a
,我相信你当前的版本会得到一些奇怪的结果…关于我的LEFT JOIN
需要在表B上的问题,你完全正确,谢谢。但是,我不确定您不需要嵌套COALESCE()
是什么意思。第一种方法是,如果您将UNION ALL
更改为UNION
,则应适用于名称的重复值。我不知道我的第二种方法,我不在sql server附近进行测试。我将在UTC上午5:00附近查看一下,然后做出响应。COALESCE()
是一个接受参数列表的函数,没有理由这样分割它。嵌套时也没有逻辑结果差异-a1
始终是首选,无论a2
或a3
的状态如何。另外,b.fkeyA3=a1.id上的表A为a3?我想你的加入会有点混乱a2
和a3
将交叉连接-您不需要再连接到TableA
两次-用或
条件替换剩下的两列(并更新COALESCE()
),您应该很好。@X-Zero我不知道COALESCE使用了两个以上的参数。原始联接的目标是分别为a1、a2和a3,但使用带有ON
子句的联接更好。感谢今晚教我一两件事:)TableB中两个具有相同名称的用户是否对应TableC中的相同Id?
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