2010-08-09 17 views
5

Tengo que escribir un script de eliminación para eliminar filas de una tabla de base de datos. Sin embargo, la tabla tiene muchas tablas de elementos secundarios (claves externas) y las tablas de elementos secundarios también tienen tablas de elementos secundarios.¿Cómo obtener la lista de tablas secundarias para una tabla de base de datos?

Existen claves foráneas para todas las relaciones y me gustaría usar esta información para obtener la lista de tablas donde tendré que eliminar, en el orden correcto (primero las tablas y luego el gráfico de dependencias).

¿Cómo puedo obtener la lista de tablas secundarias para una tabla determinada en el orden correcto?

Respuesta

5

intente esto en su base de datos, este script solo le dará el gráfico de una tabla a la vez. Supongo que tiene una tabla Empleado, pero tendría que cambiar la línea 2 para verificar una tabla específica de su base de datos:

DECLARE @masterTableName varchar(1000) 
SET @masterTableName = 'Employee' 

DECLARE @ScannedTables TABLE(Level int, Name varchar(1000) collate Latin1_General_CI_AS) 

DECLARE @currentTableCount INT 
DECLARE @previousTableCount INT 
DECLARE @level INT 

SET @currentTableCount = 0 
SET @previousTableCount = -1 
SET @level = 0 

INSERT INTO @ScannedTables VALUES (@level, @masterTableName) 

WHILE @previousTableCount <> @currentTableCount 
BEGIN 

    SET @previousTableCount = @currentTableCount 

    INSERT INTO @ScannedTables 

     SELECT DISTINCT 
      @level + 1, TC.Table_Name COLLATE Latin1_General_CI_AS 

     FROM INFORMATION_SCHEMA.TABLE_CONSTRAINTS TC 
     LEFT JOIN INFORMATION_SCHEMA.REFERENTIAL_CONSTRAINTS RC ON TC.Constraint_Name = RC.Constraint_Name 
     LEFT JOIN INFORMATION_SCHEMA.TABLE_CONSTRAINTS FTC ON RC.Unique_Constraint_Name = FTC.Constraint_Name 

     WHERE TC.CONSTRAINT_TYPE = 'FOREIGN KEY' 

     AND FTC.TABLE_NAME COLLATE Latin1_General_CI_AS IN (SELECT Name FROM @ScannedTables WHERE Level = @level) 
     AND TC.Table_Name COLLATE Latin1_General_CI_AS NOT IN (SELECT Name FROM @ScannedTables) 

    SET @level = @level + 1 

    SELECT @currentTableCount = COUNT(*) FROM @ScannedTables 
END 

SELECT * FROM @ScannedTables 
+0

Esto es exactamente lo que necesitaba. – Sylvain

1

No existe una respuesta genérica simple para esto, ya que las tablas pueden depender recursivamente de otras tablas, incluidas las relaciones propias, etc. Su resultado podría ser algo más que simple árbol.

La mejor manera debe depender de su modelo de base de datos: si tiene tablas de árbol conectadas, elimine primero sus datos de la tercera tabla, luego de la tercera, que la tercera.

... o desactivar restricciones, eliminar datos, habilitar restricciones.

... o cambie las claves externas a DELETE CASCADE.

Depende de su modelo de datos.

+0

eliminar cascada, ¡generalmente es algo malo! Puede matar el rendimiento y eliminar cuando la existencia de registros secundarios debería haber sido un stop show. – HLGEM

+0

No podría estar más de acuerdo. Sin embargo, si la base de datos completa o la tabla relacionada es muy pequeña e "insignificante", puede acelerar el desarrollo y las pruebas. – dmajkic

1

This article da una buena idea de cómo hacer lo que está preguntando.

EDIT: He modificado la consulta original dada en el enlace a:

  1. Hacer el esquema guión conscientes
  2. correcta el fallo se señala en los comentarios a continuación
No

Seguro por qué el editor está haciendo un trabajo tan pobre formateando el bloque de código.

with Fkeys as (

    select distinct 

     OnTable  = onTableSchema.name + '.' + OnTable.name 
     ,AgainstTable = againstTableSchema.name + '.' + AgainstTable.name 

    from 

     sysforeignkeys fk 

     inner join sys.objects onTable 
      on fk.fkeyid = onTable.object_id 
     inner join sys.objects againstTable 
      on fk.rkeyid = againstTable.object_id 

     inner join sys.schemas onTableSchema 
      on onTable.schema_id = onTableSchema.schema_id 

     inner join sys.schemas againstTableSchema 
      on againstTable.schema_id = againstTableSchema.schema_id 

    where 1=1 
     AND AgainstTable.TYPE = 'U' 
     AND OnTable.TYPE = 'U' 
     -- ignore self joins; they cause an infinite recursion 
     and onTableSchema.name + '.' + OnTable.name <> againstTableSchema.name + '.' + AgainstTable.name 
    ) 

,MyData as (

    select 
     OnTable = s.name + '.' + o.name 
     ,AgainstTable = FKeys.againstTable 

    from 

     sys.objects o 
      inner join sys.schemas s 
       on o.schema_id = s.schema_id 

     left join FKeys 
      on s.name + '.' + o.name = FKeys.onTable 
     left join Fkeys fk2 
      on s.name + '.' + o.name = fk2.AgainstTable 
       and fk2.OnTable = Fkeys.AgainstTable 

    where 1=1 
     and o.type = 'U' 
     and o.name not like 'sys%' 
     and fk2.OnTable is null 
    ) 

,MyRecursion as (

    -- base case 
    select 
     TableName = OnTable 
     ,Lvl  = 1 
    from 
     MyData 
    where 1=1 
     and AgainstTable is null 

    -- recursive case 
    union all select 
     TableName = OnTable 
     ,Lvl  = r.Lvl + 1 
    from 
     MyData d 
     inner join MyRecursion r 
      on d.AgainstTable = r.TableName 
) 

select 
    Lvl = max(Lvl) 
    ,TableName 
    ,strSql = 'delete from [' + tablename + ']' 
from 
    MyRecursion 
group by 
    TableName 
order by 
    1 desc 
    ,2 desc 
+0

+1 - La solución funciona en una base de datos de prueba que he creado. Sin embargo, no funciona en mi base de datos real. Me sale este error: la recursividad máxima 100 se ha agotado antes de completar la declaración. Traté de aumentar la recursión máxima y obtuve el mismo resultado. Supongo que hay un caso límite que no está cubierto por ese código y que causa recursión infinita. – Sylvain

+0

Para ese problema, agregue esto al final de la consulta: opción (maxrecursion 0). (El valor predeterminado es el número máximo permitido; también puede establecerlo en un entero> 0 si desea limitarlo a algo distinto a 100.) –

+0

No tengo tablas de hoja de más de 10 niveles. Es un error en el SQL que causa recursión infinita. – Sylvain

Cuestiones relacionadas