문제

Currently I am working in a DB with a tree-like structure. Basically there is one top level table, and there are about 10 tables that have a foreign key on that table. Each of these tables has another 10 tables with a foreign key constraint. Now my goal is to delete some records from the main table, and also delete the children, grandchildren etc. but of course the foreign keys make this a painstaking task.

I have searched a bit and came across checked this question on using cascade delete and I guess this would do the trick if I was dealing with only a few tables. However, in my current setting it would still not be pleasant to alter over 100 tables one by one.

Therefore I am asking whether there is an easy way to delete values that have foreign keys when many tables are involved.

As I have some control over the relatively small DB, query efficiency and the risk of values being deleted by others are not really a concern. So it may be easy to apply cascade delete on all tables, but I am also open to completely different solutions (Using T-SQL in microsoft server studio 2008).

도움이 되었습니까?

해결책 2

The delete cascade would be a good solution for a "main" table.

To avoid altering manually all your tables, you can use a script, as found here with a minor change (last line, change <yourTable> by your table Name).

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>')

You copy the first column result in a Management Studio query window, execute, then do the same with the second column, and voilà, you're done.

다른 팁

have you looked at this? This guy is autogenerating the delete statement based on foreign key relationships in database:

Generate Delete Statement From Foreign Key Relationships in SQL 2008?

I am not personally a big fan of it but it's something to try.

I think the best way to do something like this, in a different way, is to use a logic deletion, with a column named "status" or so that controls if that field is still to be considered under your program logic. The status column has to be created only on the top-level table. When in an SQL statement, you insert an "where status = 1" or something like that.

Hope that helps, since it's an entirely different approach to the question.

Unless you are willing to sacrifice data integrity, utilize the T_SQL CASCADE DELETE option. You can create an "ALTER TABLE PARENT1 ADD FOREIGN KEY" and copy and paste your way to a safe solution.

This will take far less time than developing and testing a programmatic solution, which will not be executed if a delete statement is issued through a third-party program - like Mgmt. Studio.

As was stated in the question you referenced you can automatically take care of the deletion through the use of the ON DELETE CASCADE.

라이센스 : CC-BY-SA ~와 함께 속성
제휴하지 않습니다 StackOverflow
scroll top