Pergunta

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

Foi útil?

Solução 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.

Outras dicas

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.

Licenciado em: CC-BY-SA com atribuição
Não afiliado a StackOverflow
scroll top