重複エントリを作成せずに SQL テーブル内の連絡先をマージする
-
02-07-2019 - |
質問
ListID と PersonID という 2 つの列だけを保持するテーブルがあります。システム内である人物が別の人物とマージされるとき、「ソース」人物からのすべての参照を「宛先」人物への参照に更新する必要がありました。
理想的には、次のような単純なものを呼び出したいと思います
UPDATE MailingListSubscription
SET PersonID = @DestPerson
WHERE PersonID = @SourcePerson
ただし、送信元の人物と同じ ListID を持つ宛先の人物がすでにこのテーブルに存在する場合、重複したエントリが作成されます。重複したエントリを作成せずにこのアクションを実行するにはどうすればよいですか?(ListID、PersonalIDが主キー)
編集:複数の ListID が使用されています。SourcePerson が ListID 1、2、および 3 に割り当てられ、Destinationperson が ListID 3 および 4 に割り当てられている場合、最終結果には 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
他のヒント
まず、Sourceperson が購読している、Destperson がまだ購読していないすべてのリストに 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
ここでは David B の意見に同意せざるを得ません。そこにあるべきではない古いものをすべて削除してから、更新を実行します。
実際、あなたが提案しているようにレコードの主キーを変更する状況は本来あってはならないため、データベースの設計に戻って再検討する必要があると思います。これは、PersonID 列が実際には変更されていないことを意味します。まず適切な主キーを用意します。
私の推測では、あなたの PersonID がユーザーに公開されており、ユーザーが何らかの理由でデータベースの番号を変更し、その変更を再度同期しているのだと思います。これは、監査証跡と一時的な一貫性を損なうため、一般的には悪いアイデアです。このような状況では、一般に、変更しない独自の主キー (通常は ID) を使用し、その属性としてユーザーに表示される PersonID を設定することをお勧めします。余分な作業ですが、長期的にはさらなる一貫性と堅牢性が得られます。
経験則として、レコードの主キーは可能な限りユーザーに公開すべきではなく、慎重に検討した後にのみ公開する必要があります。OK、私自身、何度もこれを破ってしまったことを告白しますが、できるところから努力する価値はあります :-)