T-SQL“合并”两行,或“重新设置”所有FK关系
我有一个生产数据库,其中偶尔需要合并单个表中的冗余行 让我们假设这个表中的两行都有相同的值,除了它们的IDT-SQL“合并”两行,或“重新设置”所有FK关系,sql,sql-server,tsql,Sql,Sql Server,Tsql,我有一个生产数据库,其中偶尔需要合并单个表中的冗余行 让我们假设这个表中的两行都有相同的值,除了它们的ID Table "PrimaryStuff" ID | SomeValue 1 | "I have value" 2 | "I have value" 3 | "I am different" 我们还假设存在许多相关的表。因为重复项是在PrimaryStuff表中创建的,所以通常在这些子表中创建的行都应该与PrimaryStuff表上的单个记录相关。这些表的数量和名称不在我的控制之下,
Table "PrimaryStuff"
ID | SomeValue
1 | "I have value"
2 | "I have value"
3 | "I am different"
我们还假设存在许多相关的表。因为重复项是在PrimaryStuff表中创建的,所以通常在这些子表中创建的行都应该与PrimaryStuff表上的单个记录相关。这些表的数量和名称不在我的控制之下,应该在运行时动态考虑。IE:我不知道相关记录的名称甚至数量,因为其他人可能会在我不知道的情况下编辑数据库
Table "ForeignStuff"
ID | PrimaryStuffId | LocalValue
1| 1| "I have the correct FK"
2| 1| "I have the correct FK"
3| 2| "I should get pointed to an FK of 1"
为了解决PrimaryStuff的第1行和第2行的重复问题,我希望所有相关表都将其FK更改为1s,然后删除PrimaryStuff的第2行。这应该很简单,就像PrimaryStuff的第1行不存在一样,我可以将第2行的主键更新为第1行,这样更改就会层叠而出。我不能这样做,因为这将是PrimaryStuff唯一索引中的重复键
请随意提问,我会尽力澄清任何令人困惑的问题。首先让我们获得需要更新的行列表,据我所知,您希望最低ID替换所有较高ID
SELECT MIN(ID) OVER (PARTITION BY SomeValue ORDER BY SomeValue, ID ASC) AS FirstID,
ID,
SOMEVALUE
FROM PrimaryStuff
我们可以删除FirstID和ID匹配的,这些都不重要
SELECT FirstID, ID FROM
(
SELECT MIN(ID) OVER (PARTITION BY SomeValue ORDER BY SomeValue, ID ASC) AS FirstID,
ID,
SOMEVALUE
FROM PrimaryStuff
) T
WHERE FirstID != ID
现在我们有一个变更列表。我们可以在update语句中使用它,将它放在临时表或CTE中,正如我在下面所做的:
WITH ChangeList AS
(
SELECT FirstID, ID FROM
(
SELECT MIN(ID) OVER (PARTITION BY SomeValue ORDER BY SomeValue, ID ASC) AS FirstID,
ID
FROM PrimaryStuff
) T
WHERE FirstID != ID
)
UPDATE ForeignStuff
SET PrimaryStuffId = ChangeList.FirstID
FROM ForeignStuff
JOIN ChangeList ON ForeignStuff.ID = ChangeList.ID
注意-未测试的代码可能有拼写错误。您是否可以更主动地使用现有ID(当SomeValue已经存在时)并对PrimaryStuff.SomeValue强制执行唯一约束,或者为什么不将SomeValue作为PrimaryStuff的主键。使用它作为PrimaryKey,只有当PrimaryStuff中不存在某个值时,才能将记录添加到PrimaryStuff中 最后,也是最简单的一点,如果某个值总是被其他人任意定义,而你拿走了他们给你的任何东西,为什么不干脆放弃PrimaryStup,让用户在ForeignStuff中输入他们想要的任何东西呢?如果需要SomeValue的唯一列表,请基于主表创建一个视图。如果需要加快查询速度,请向ForeignStuff.SomeValue字段添加索引 当存在多个表(如ForeignStuff)时,这是一个未经测试的视图:
-- dynamically generate a distinct list of values of interest
select SomeValue from ForeignStuffA
union select SomeValue from ForeignStuffB
union select SomeValue from ForeignStuffC
-- and so on, the union applies distinct
谢谢你的回复,霍根。你走上正轨了。不过,你确实错过了美中不足的机会,这是一个棘手的问题:我如何处理n个ForeignStuff表,其中n表示未知数量的表,如ForeignStuff,其中包含PrimarySuff表的外键。@OliverKane-只需为每个表运行脚本,或者,如果您需要使用上述内容作为模板自动编写动态SQL。在这种情况下,您可能希望使用临时表而不是CTE来提高多个查询的性能。@OliverKane-如果您不理解,在我修改ForeignStuff表之前,我的解决方案并不关心这些表——在此之前,我只是准备好了。事实上,我刚刚根据您的工作拼凑出一个存储过程来完成这项工作。答案授予您,好心的先生。@FélixGagnon Grenier-对。下面是一些不严肃的SQL->将MONKEY插入桶中,其中FUN
是否在国外数据库中?我同意,尽管我不愿意把所有的内部关系都抛到这张桌子上。除了这个用例之外,它的行为就像是本地的一样。此外,如果您还没有,您可能希望查找DDD概念,如上下文映射、有界上下文、反腐败层、一致性,以便了解从其他输出到下游的权衡,以及什么可能最适合您的情况。