MS SQL将旧表拆分为多对多关系

时间:2019-01-10 12:13:23

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

我有一个旧表,其中有很多列,我想将其拆分成3个表,并具有多对多关系。

旧表没有标识列。

旧桌子:

CustomerNumber
FirstName
LastName
Address
Postal
City
....

新表格

客户:

Id
Customernumber
Firstname
Lastname
... ect

地址:

Id
Address
Postal
City
... ect

CustomerAddress

Id
CustomerId
AddressId

现在如何使用SQL将旧表散布到新表中?

我尝试过使用MERGE,但那一次最多只能处理一张桌子。一种选择是使用CURSOR,但我读到使用它或迭代是一个坏主意,但目前这是我为此找到的唯一解决方案。

declare 
@CustomerId bigint,
@CustomerNumber float, 
@Status int,
@Address varchar(50),
@RoadNumber int,
@LastEdited datetime,

@AddressId bigint

declare my_cursor cursor
local static read_only forward_only
for
    select CustomerNumber, Address, Housenumber, Status, Date
    from [db1].dbo.OldCustomer k
    where 
        FIRMANR in (1, 40, 60, 80, 90, 120, 180, 400)

    open my_cursor
    fetch next from my_cursor into @CustomerNumber, @Address, @RoadNumber, @Status, @LastEdited
while @@FETCH_STATUS = 0
begin
    --if the customer already exists we get the identity
    if exists (select Id from [db2].dbo.Customers where CustomerNumber = @CustomerNumber)
        select @CustomerId = Id from [db2].dbo.Customers where CustomerNumber = @CustomerNumber

    --if the customer does not exit we need to insert and retrieve the new Identity value
    else
        begin
            -- insert the customer
            insert into [db2].dbo.Customers (CustomerNumber, [Status], LastEdited) values (@CustomerNumber, @Status, @LastEdited)
            set @CustomerId = SCOPE_IDENTITY()
        end

    -- get address if it already exists
    if exists (select Id from [db2].dbo.Addresses where Road = @Address and Roadnumber = @RoadNumber)
        select @AddressId = Id from [db2].dbo.Addresses where Road = @Address and Roadnumber = @RoadNumber
    else
        begin
            -- insert new addresses
            insert into [db2].dbo.Addresses (Road,Roadnumber) values (@Address, @RoadNumber)
            set @AddressId = SCOPE_IDENTITY()
        end

    -- insert customer => address reference if it does not exist
    if not exists (select Id from [db2].dbo.CustomerAddress where CustomerId = @CustomerId and AddressId = @AddressId)
        -- insert customer => address reference
        insert into [db2].dbo.CustomerAddress(CustomerId,AddressId) values (@CustomerId, @AddressId)


    fetch next from my_cursor into @CustomerNumber, @Address, @RoadNumber, @Status, @LastEdited
end

close my_cursor
deallocate my_cursor

1 个答案:

答案 0 :(得分:0)

这可能是最简单的:

  • 为老客户添加一个名为AddressId的列
  • 使用唯一的ID填充它(您可以重复使用Customer ID,或者如果其GUID使用NewID())
  • 为地址和客户地址创建新表
  • 将部分旧客户数据插入每个新表中
  • 来自客户的与地址有关的列

--populate new Address table
INSERT INTO Address(id,col1,col2...)
SELECT AddressID, col1, col2... FROM Customer

--populate new CustomerAddress table
INSERT INTO CustomerAddress(CustomerId,AddressId)
SELECT Id, AddressID FROM Customer

使用SQLS,您可以将其作为一个简单的脚本执行此操作,如果需要的话,也可以使用事务进行。不需要存储过程,游标,合并等。

不要给CustomerAddress自己的ID列; CustomerAddress的主键是CustomerId和AddressId的组合;制作复合PK,而不是单独的

Tbh,我可能没有CustomerAddress表,而在customer中只有BillingAddressId,WorkAddressId,HomeAddressId,ShippingAddressId列,但是如何管理此内容取决于您;如果您有很多地址并且类型各异,那么可以肯定地进行M:M分解,但是如果实际上您的客户最多只能有3个地址,等等,我会坚持使用一个命名列来说明该地址是什么在客户中

如果要使用CustomerAddress表,请考虑添加一列来声明地址的类型/原因