通过删除重复项将One-One关系修复为One-Many

问题描述 投票:0回答:2

错误

最初,Orgs和Servers之间存在一对一的关系,其中Server的关键只是一个OrganizationId,这是一个非常糟糕的设计,因为业务逻辑已经改变,现在多个Orgs可以拥有相同的服务器。在我们进行更改之前,我们只为每个组织复制了服务器,因此多个组织将具有相同子域的服务器。以下是当前设置。

要求

首先,不幸的是,这有很多数据,所以用正确的模型删除整个数据库是不合适的。

我们想要做的是现在删除不同子域上的重复服务器,例如,如果Org1和Org2的Ser1和Ser2都具有子域“test”,我们会使FK Org.Server_Id成为服务器的最低位置域,在本例中为Ser1,因此对于Org1和Org2,它们的服务器将是Ser1。以下是高科技excel示例:

我们尝试过的事情

我们能够通过以下方式将Org.Server_Id变为基于Server.OrganizationId的正确值:

UPDATE Organization 
SET Server_Id = t.Id
FROM(
    SELECT Id, OrganizationId
    FROM Server
) t
WHERE t.OrganizationId = Organization.Id

但是每当我们尝试更进一步时,我们就会陷入困境,因为我们无法在内部FROM中使用ORDER BY来尝试以某种聚合方式获取第一个匹配项。

这是我们最终得到的,但当然它不起作用,因为我们无法访问内部的内部,我也不认为这甚至是正确的路径:

UPDATE Organization SET Server_Id = t.Id  
FROM  
(  
    SELECT Id, OrganizationId
    FROM (
        SELECT TOP(1) Subdomain, Id, OrganizationId
        FROM Server
        WHERE Subdomain = t.Subdomain
    ) a
) t  
WHERE t.OrganizationId = Organization.Id
sql sql-server duplicates
2个回答
1
投票

我不能说我完全理解你所做的一切,但在过去当我需要抓住重复信息的第一个条目时,我在内部查询中使用了分区函数。我不知道你想如何订购结果,但它看起来像这样:

 (
 SELECT ROW_NUMBER() OVER (PARTITION BY column1, column2, etc... ORDER BY columnX DESC/ASC) As row_num, Id, OrganizationId
 FROM Server
 ) t
 WHERE t.OrganizationId = Organization.Id AND row_num = 1

这与你在第二个代码块中尝试做的事情基本相同(我相信)。 column1和column2将是您要折叠到一个条目中的重复数据列的集合,columnX将是按顺序排序结果的列。通过在WHERE语句中使用row_num = 1,您只能从内部查询中获取每个唯一column1,column2等的第一个结果。


0
投票

使用@ user2731076建议的分区后,我们可以将查询修改为:

UPDATE Organization SET Server_Id = t.Id  
FROM  
(
    SELECT ROW_NUMBER() OVER (PARTITION BY Subdomain ORDER BY [Server].Id ASC) As row_num, [Server].Id, OrganizationId, Subdomain
    FROM Organization
    INNER JOIN [Server] ON [Server].OrganizationId = [Organization].Id
) t
WHERE t.Subdomain IN(SELECT Subdomain FROM Server WHERE OrganizationId = Organization.Id) AND row_num = 1

我们的代码遇到的问题:

t.OrganizationId = Organization.Id

是因为总有一个服务器与一个Org相关联,它只是将Org.Server_Id的值设置为它已经设置的值。所以我们想要找到的第一个实例是具有类似于当前Org服务器的子域的子域的服务器的row_num = 1。这需要Inner Join从分区中获取它,并通过WHERE子句中的IN语句从当前组织中获取它,因此我们可以为我们的Org执行t.Subdomain = subdomain。

可能有一种更有效的方法,我们将来会对此进行研究。

© www.soinside.com 2019 - 2024. All rights reserved.