【问题标题】:Delete from a table with many foreign keys从具有许多外键的表中删除
【发布时间】:2013-01-07 04:33:41
【问题描述】:

目前我正在一个具有树状结构的数据库中工作。基本上有一个顶级表,大约有 10 个表在该表上有一个外键。这些表中的每一个都有另外 10 个具有外键约束的表。现在我的目标是从主表中删除一些记录,同时删除子、孙等。当然,外键使这成为一项艰巨的任务。

我进行了一些搜索,并在使用级联删除时遇到了检查这个question,我想如果我只处理几个表,这将起到作用。但是,在我目前的设置中,一张一张地改变 100 多张桌子仍然不是一件令人愉快的事情。

因此,我想问是否有一种简单的方法可以在涉及许多表时删除具有外键的值。

由于我对相对较小的数据库有一定的控制权,因此查询效率和值被其他人删除的风险并不是真正值得关注的问题。因此,对所有表应用级联删除可能很容易,但我也对完全不同的解决方案持开放态度(在 microsoft server studio 2008 中使用 T-SQL)。

【问题讨论】:

  • 这取决于,虽然您删除了父记录,但您是否要将这些值保留在子记录中以用于历史记录目的?
  • @bonCodigo 不,我也真的想删除孩子。

标签: sql sql-server-2008 tsql cascading-deletes


【解决方案1】:

我认为以不同的方式执行此类操作的最佳方法是使用逻辑删除,使用名为“状态”的列来控制是否仍要在程序逻辑下考虑该字段。只能在顶级表上创建状态列。在 SQL 语句中,插入“where status = 1”或类似的内容。

希望有所帮助,因为这是解决问题的完全不同的方法。

【讨论】:

  • 这意味着更改他们在应用程序中的每个查询以说明逻辑删除的列。级联删除会便宜很多
  • 我想我明白这一点,但如果这意味着我仍然必须创建连接来跟踪这个值,它似乎不是一个有用的解决方案。
  • 昂贵。好主意。
  • 再读一遍,相信我们已经有了这样的东西。在多个级别上,可以使记录处于非活动状态,之后它及其子项将不再影响程序。然而,这不是我正在寻找的“删除”。不过感谢您的回答!
【解决方案2】:

删除级联对于“主”表来说是一个很好的解决方案。

为避免手动更改所有表,您可以使用脚本,如发现的 here 并稍作更改(最后一行,将 <yourTable> 更改为您的表名称)。

select
  DropStmt = 'ALTER TABLE [' + ForeignKeys.ForeignTableSchema + 
      '].[' + ForeignKeys.ForeignTableName + 
      '] DROP CONSTRAINT [' + ForeignKeys.ForeignKeyName + ']; '
,  CreateStmt = 'ALTER TABLE [' + ForeignKeys.ForeignTableSchema + 
      '].[' + ForeignKeys.ForeignTableName + 
      '] WITH CHECK ADD CONSTRAINT [' +  ForeignKeys.ForeignKeyName + 
      '] FOREIGN KEY([' + ForeignKeys.ForeignTableColumn + 
      ']) REFERENCES [' + schema_name(sys.objects.schema_id) + '].[' +
  sys.objects.[name] + ']([' +
  sys.columns.[name] + ']) ON DELETE CASCADE; '
 from sys.objects
  inner join sys.columns
    on (sys.columns.[object_id] = sys.objects.[object_id])
  inner join (
    select sys.foreign_keys.[name] as ForeignKeyName
     ,schema_name(sys.objects.schema_id) as ForeignTableSchema
     ,sys.objects.[name] as ForeignTableName
     ,sys.columns.[name]  as ForeignTableColumn
     ,sys.foreign_keys.referenced_object_id as referenced_object_id
     ,sys.foreign_key_columns.referenced_column_id as referenced_column_id
     from sys.foreign_keys
      inner join sys.foreign_key_columns
        on (sys.foreign_key_columns.constraint_object_id
          = sys.foreign_keys.[object_id])
      inner join sys.objects
        on (sys.objects.[object_id]
          = sys.foreign_keys.parent_object_id)
        inner join sys.columns
          on (sys.columns.[object_id]
            = sys.objects.[object_id])
           and (sys.columns.column_id
            = sys.foreign_key_columns.parent_column_id)
    ) ForeignKeys
    on (ForeignKeys.referenced_object_id = sys.objects.[object_id])
     and (ForeignKeys.referenced_column_id = sys.columns.column_id)
 where (sys.objects.[type] = 'U')
  and (sys.objects.[name]  = '<yourTable>')

您在 Management Studio 查询窗口中复制第一列结果,执行,然后对第二列执行相同操作,瞧,大功告成。

【讨论】:

  • 我知道我应该用我的表名替换yourtable。但是我怎样才能表明我要删除字段IsActive = 0 所在的记录。之后我如何将外键设置为原始状态?
  • @DennisJaheruddin 这不是“IsActive = 0”的版本。这是启用级联删除的版本。所以记录将被删除(没有“IsActive”的问题。所以我们的想法是不要将外键恢复到原来的状态。但如果你想,只需重新传递脚本,移动“ON DELETE CASCADE”部分。
  • 谢谢,恢复外键看起来很简单。那么我是否正确理解该脚本实际上并未删除任何内容,而只是使其成为可能?然后我可以自己删除条目?
  • @DennisJaheruddin 是的,你理解得很好。它只是启用 ON DELETE CASCADE 行为。
【解决方案3】:

你看过这个吗?这家伙正在根据数据库中的外键关系自动生成删除语句:

Generate Delete Statement From Foreign Key Relationships in SQL 2008?

我个人不是它的忠实粉丝,但可以尝试一下。

【讨论】:

  • 我知道我应该用我的表名替换MyTableName。但是我怎样才能表明我要删除字段IsActive = 0 所在的记录。完成后我是否需要做任何事情来确保数据库再次“安全”?
【解决方案4】:

正如您引用的问题中所述,您可以通过使用 ON DELETE CASCADE 自动处理删除。

【讨论】:

  • 但是如果不访问大量表(以后可能会添加更多)并一一更改它们,我怎么能做到这一点?
  • 修改脚本很简单。一点点数据库管理现在可以在很长一段时间后进行。替代方案是 1) 首先使用父表中的键从基础表中删除信息,然后删除父表中的信息。 2)使用另一个答案中建议的删除标志。要么比我的建议更难维护,要么更贵。
【解决方案5】:

除非您愿意牺牲数据完整性,否则请使用 T_SQL CASCADE DELETE 选项。您可以创建“ALTER TABLE PARENT1 ADD FOREIGN KEY”并复制并粘贴到安全解决方案中。

这将比开发和测试程序化解决方案花费的时间少得多,如果删除语句是通过第三方程序(如 Mgmt)发出的,则不会执行该程序化解决方案。工作室。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2019-10-10
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2013-03-02
    • 2015-12-08
    相关资源
    最近更新 更多