合并SQL表中的联系人而不创建重复的条目

时间:2020-03-06 14:44:27  来源:igfitidea点击:

我有一个表,仅包含两列ListID和PersonID。当一个人与系统中的另一个人合并时,我将把"源"人的所有引用更新为对"目的地"人的引用。

理想情况下,我想称呼类似

UPDATE MailingListSubscription
SET PersonID = @DestPerson
WHERE PersonID = @SourcePerson

但是,如果此表中已经存在目标人,并且其ID与源人具有相同的ListID,则将进行重复输入。如何在不创建重复条目的情况下执行此操作? (ListID,PersonID为主键)

编辑:使用多个ListID。如果将SourcePerson分配给ListID 1、2和3,并将DestinationPerson分配给ListID 3和4,则最终结果需要将四行DestinationPerson分配给ListID 1、2、3和4.

解决方案

--out with the bad
DELETE
FROM MailingListSubscription
WHERE PersonId = @SourcePerson
  and ListID in (SELECT ListID FROM MailingListSubscription WHERE PersonID = @DestPerson)

--update the rest (good)
UPDATE MailingListSubscription
SET PersonId = @DestPerson
WHERE PersonId = @SourcePerson

我必须在这里同意大卫B的观点。删除所有不该存在的较旧的内容,然后进行更新。

实际上,我认为我们应该返回并重新考虑数据库设计,因为我们实际上不应该在更改记录的主键的情况下(因为我们打算这样做)意味着PersonID列实际上不是首先是合适的主键。

我的猜测是PersonID暴露给用户,由于某种原因,他们已对其数据库重新编号,并且我们正在同步更改。这通常是一个糟糕的主意,因为它破坏了审核记录和时间一致性。在这种情况下,通常最好使用我们自己的不变主键(通常是一个标识)并设置PersonID(用户将其视为该属性的一个属性)。这是额外的工作,但从长远来看,它将为我们提供额外的一致性和鲁棒性。

一个好的经验法则是,记录的主键不应在可能的情况下向用户公开,只有在仔细考虑后才可以这样做。好吧,我承认自己在很多场合都打破了自己,但是值得在你能做到的地方努力:-)

首先,我们应该将destperson订阅到SourcePerson所订阅的Destperson尚未被订阅的所有列表。然后删除所有SourcePersons订阅。
这将与多个ListID一起使用。

Insert into MailingListSubscription
(
   ListID,
   PersonID
)
Select
   ListID,
   @DestPerson
From
   MailingListSubscription as t1
Where
   PersonID = @SourcePerson and
   Not Exists
   (
      Select *
      From MailingListSubscription as t2
      Where
         PersonID = @DestPerson and
         t1.ListID = t2.ListID
   )

Delete From MailingListSubscription
Where
   PersonID = @SourcePerson