none
Eliminar registros en tablas ralcionales RRS feed

  • Pregunta

  • Mi pregunta es la siguiente: como hago para eliminar un registro en 4 tablas. por ejemplo tengo una tabla que se llama Producto, Factura, Cliente y Detalle. mi relación esta asi, la tabla producto se relaciona con  la tabla detalle la tabla Cliente con la tabla factura y esta a su vez se relaciona con la tabla detalle.

    Si yo quiero eliminar por ejemplo una factura que debo hacer entones....

    o si yo quiero eliminar un producto que debo hacer...

    Agradezco mucho su ayuda....

    sábado, 5 de marzo de 2011 17:11

Respuestas

  • La respuesta depende de que lado de la relacion quieres eliminar la fila.

    1 - Lado hijo (factura - cliente / detalle - producto / detalle - factura)

    En este caso solo basta con eliminar la fila.

    2 - Lado padre (factura - detalle / producto - detalle / cliente - factura)

    En este caso debes tener en cuenta que al eliminar una fila en el padre, no dejes huerfano algun hijo. Por ejemplo, si deseas eliminar un producto enotnces debes tener en cuenta si existe o no algun detalle de factura que lo referencie.

    Existen varias formas de implementar esto a nivel de SQL Server:

    2.1 - Usando restricciones referenciales en cascada como son "ON DELETE ...", las cuales te permiten cuatro tipos de accion:

        2.1.1 - NO ACTION
        2.1.1 - CASCADE
        2.1.1 - SET NULL
        2.1.1 - SET DEFAULT

    Esta forma de implementacion permite que si borras una fila en el padre, entonces con la opcion "NO ACTION" se le indica a SQL Server que no tome ninguna accion y por lo tanto si existe algun hijo referenciando al padre entonces dara error puesto que la operacion dejaria a la fila en el hijo como huerfana (apunta a un padre que no existe).  Esta opcion (NO ACTION) es la usada por defecto cuando se usa una restriccion tipo clave foranea.

    USE tempdb;
    GO
    CREATE TABLE dbo.T1 (
    c1 int NOT NULL CONSTRAINT PK_T1 PRIMARY KEY,
    c2 varchar(25) NOT NULL
    );
    GO
    CREATE TABLE dbo.T2 (
    sk int NOT NULL IDENTITY(1, 1) CONSTRAINT PK_T2 PRIMARY KEY,
    c1 int NULL
    	CONSTRAINT FK_T2_T1 REFERENCES dbo.T1(c1) ON DELETE NO ACTION,
    	--CONSTRAINT FK_T2_T1 REFERENCES dbo.T1(c1) ON DELETE SET NULL,
    	--CONSTRAINT DF_T2_c1 DEFAULT (3)
    	--CONSTRAINT FK_T2_T1 REFERENCES dbo.T1(c1) ON DELETE SET DEFAULT,
    c2 varchar(25) NOT NULL
    );
    GO
    INSERT INTO dbo.T1(c1, c2) VALUES(1, 'uno');
    INSERT INTO dbo.T1(c1, c2) VALUES(2, 'dos');
    
    INSERT INTO dbo.T2(c1, c2) VALUES(1, 'referencia a uno');
    INSERT INTO dbo.T2(c1, c2) VALUES(2, 'referencia a dos');
    
    SELECT * FROM dbo.T1;
    SELECT * FROM dbo.T2;
    
    DELETE dbo.T1
    WHERE c1 = 1;
    
    SELECT * FROM dbo.T1;
    SELECT * FROM dbo.T2;
    GO
    DROP TABLE dbo.T2, dbo.T1;
    GO
    

    Si escojemos "SET NULL", entonces la columna que se usa para referenciar al padre es puesta en NULL y terminamos con una fila huerfana pero que no apunta a nada.

    USE tempdb;
    GO
    CREATE TABLE dbo.T1 (
    c1 int NOT NULL CONSTRAINT PK_T1 PRIMARY KEY,
    c2 varchar(25) NOT NULL
    );
    GO
    CREATE TABLE dbo.T2 (
    sk int NOT NULL IDENTITY(1, 1) CONSTRAINT PK_T2 PRIMARY KEY,
    c1 int NULL
    	--CONSTRAINT FK_T2_T1 REFERENCES dbo.T1(c1) ON DELETE NO ACTION,
    	CONSTRAINT FK_T2_T1 REFERENCES dbo.T1(c1) ON DELETE SET NULL,
    	--CONSTRAINT DF_T2_c1 DEFAULT (3)
    	--CONSTRAINT FK_T2_T1 REFERENCES dbo.T1(c1) ON DELETE SET DEFAULT,
    c2 varchar(25) NOT NULL
    );
    GO
    INSERT INTO dbo.T1(c1, c2) VALUES(1, 'uno');
    INSERT INTO dbo.T1(c1, c2) VALUES(2, 'dos');
    
    INSERT INTO dbo.T2(c1, c2) VALUES(1, 'referencia a uno');
    INSERT INTO dbo.T2(c1, c2) VALUES(2, 'referencia a dos');
    
    SELECT * FROM dbo.T1;
    SELECT * FROM dbo.T2;
    
    DELETE dbo.T1
    WHERE c1 = 1;
    
    SELECT * FROM dbo.T1;
    SELECT * FROM dbo.T2;
    GO
    DROP TABLE dbo.T2, dbo.T1;
    GO
    

    Si usamos "SET DEFAULT", entonces en la columna usada para referenciar al padre se pondra un valor por defecto que se declaro durante la definicion de la tabla. Si este valor por defecto es diferente de NULL y la fila padre a la que referencia no existe, entonces obtendremos un error.

    USE tempdb;
    GO
    CREATE TABLE dbo.T1 (
    c1 int NOT NULL CONSTRAINT PK_T1 PRIMARY KEY,
    c2 varchar(25) NOT NULL
    );
    GO
    CREATE TABLE dbo.T2 (
    sk int NOT NULL IDENTITY(1, 1) CONSTRAINT PK_T2 PRIMARY KEY,
    c1 int NULL
    	--CONSTRAINT FK_T2_T1 REFERENCES dbo.T1(c1) ON DELETE NO ACTION,
    	--CONSTRAINT FK_T2_T1 REFERENCES dbo.T1(c1) ON DELETE SET NULL,
    	CONSTRAINT DF_T2_c1 DEFAULT (3)
    	CONSTRAINT FK_T2_T1 REFERENCES dbo.T1(c1) ON DELETE SET DEFAULT,
    c2 varchar(25) NOT NULL
    );
    GO
    INSERT INTO dbo.T1(c1, c2) VALUES(1, 'uno');
    INSERT INTO dbo.T1(c1, c2) VALUES(2, 'dos');
    
    INSERT INTO dbo.T2(c1, c2) VALUES(1, 'referencia a uno');
    INSERT INTO dbo.T2(c1, c2) VALUES(2, 'referencia a dos');
    
    SELECT * FROM dbo.T1;
    SELECT * FROM dbo.T2;
    
    DELETE dbo.T1
    WHERE c1 = 1;
    
    SELECT * FROM dbo.T1;
    SELECT * FROM dbo.T2;
    GO
    DROP TABLE dbo.T2, dbo.T1;
    GO
    
    

    Es de notar que estoy usando el valor por defecto (3) y que esa fila en el padre no existe, por lo que te dara un error cuando tratas de eliminar un padre con hijos. Si cambias el valor por defecto a (2), en este ejemplo, veras que los hijos del padre "c1 = 1" ahora apuntan al padre "c1 = 2".

    Por ultimo esta opcion "CASCADE" la cual eliminara todos los hijos de forma automatica en cascada. Esta opcion es util pero riesgosa puesto que si se elimina una fila padre por error, por ejemplo un cliente, entonces los hijos seran eliminados tambien (facturas).

    USE tempdb;
    GO
    CREATE TABLE dbo.T1 (
    c1 int NOT NULL CONSTRAINT PK_T1 PRIMARY KEY,
    c2 varchar(25) NOT NULL
    );
    GO
    CREATE TABLE dbo.T2 (
    sk int NOT NULL IDENTITY(1, 1) CONSTRAINT PK_T2 PRIMARY KEY,
    c1 int NULL
    	--CONSTRAINT FK_T2_T1 REFERENCES dbo.T1(c1) ON DELETE NO ACTION,
    	--CONSTRAINT FK_T2_T1 REFERENCES dbo.T1(c1) ON DELETE SET NULL,
    	--CONSTRAINT DF_T2_c1 DEFAULT (3)
    	--CONSTRAINT FK_T2_T1 REFERENCES dbo.T1(c1) ON DELETE SET DEFAULT,
    	CONSTRAINT FK_T2_T1 REFERENCES dbo.T1(c1) ON DELETE CASCADE,
    c2 varchar(25) NOT NULL
    );
    GO
    INSERT INTO dbo.T1(c1, c2) VALUES(1, 'uno');
    INSERT INTO dbo.T1(c1, c2) VALUES(2, 'dos');
    
    INSERT INTO dbo.T2(c1, c2) VALUES(1, 'referencia a uno');
    INSERT INTO dbo.T2(c1, c2) VALUES(2, 'referencia a dos');
    
    SELECT * FROM dbo.T1;
    SELECT * FROM dbo.T2;
    
    DELETE dbo.T1
    WHERE c1 = 1;
    
    SELECT * FROM dbo.T1;
    SELECT * FROM dbo.T2;
    GO
    DROP TABLE dbo.T2, dbo.T1;
    GO
    

    2.2 - La otra opcion seria usar "NO ACTION" y controlar la eliminacion de forma procedural. De esta forma puedes chequear si existen hijos o no y proceder con la eliminacion en caso deseado.

    USE tempdb;
    GO
    CREATE TABLE dbo.T1 (
    c1 int NOT NULL CONSTRAINT PK_T1 PRIMARY KEY,
    c2 varchar(25) NOT NULL
    );
    GO
    CREATE TABLE dbo.T2 (
    sk int NOT NULL IDENTITY(1, 1) CONSTRAINT PK_T2 PRIMARY KEY,
    c1 int NULL
    	CONSTRAINT FK_T2_T1 REFERENCES dbo.T1(c1) ON DELETE NO ACTION,
    	--CONSTRAINT FK_T2_T1 REFERENCES dbo.T1(c1) ON DELETE SET NULL,
    	--CONSTRAINT DF_T2_c1 DEFAULT (3)
    	--CONSTRAINT FK_T2_T1 REFERENCES dbo.T1(c1) ON DELETE SET DEFAULT,
    	--CONSTRAINT FK_T2_T1 REFERENCES dbo.T1(c1) ON DELETE CASCADE,
    c2 varchar(25) NOT NULL
    );
    GO
    INSERT INTO dbo.T1(c1, c2) VALUES(1, 'uno');
    INSERT INTO dbo.T1(c1, c2) VALUES(2, 'dos');
    INSERT INTO dbo.T1(c1, c2) VALUES(3, 'tres');
    
    INSERT INTO dbo.T2(c1, c2) VALUES(1, 'referencia a uno');
    INSERT INTO dbo.T2(c1, c2) VALUES(2, 'referencia a dos');
    
    SELECT * FROM dbo.T1;
    SELECT * FROM dbo.T2;
    GO
    CREATE PROCEDURE dbo.usp_T1_del
    @c1 int
    AS
    SET NOCOUNT ON;
    SET XACT_ABORT ON;
    
    BEGIN TRY
    	BEGIN TRANSACTION;
    	
    	IF NOT EXISTS (SELECT * FROM dbo.T2 WHERE c1 = @c1)
    		DELETE dbo.T2 WHERE c1 = @c1;
    	ELSE
    		RAISERROR ('No se puede eliminar padre %i, por que tiene hijos.', 16, 1, @c1);
    
    	DELETE dbo.T1 WHERE c1 = @c1;
    	
    	COMMIT TRANSACTION;
    	
    	RETURN 0;
    END TRY
    BEGIN CATCH
     IF @@TRANCOUNT > 0
    		ROLLBACK TRANSACTION;
    	
    	SELECT
    		ERROR_NUMBER() AS ErrorNumber
    		,ERROR_SEVERITY() AS ErrorSeverity
    		,ERROR_STATE() AS ErrorState
    		,ERROR_PROCEDURE() AS ErrorProcedure
    		,ERROR_LINE() AS ErrorLine
    		,ERROR_MESSAGE() AS ErrorMessage;
    
    	RETURN -1;
    END CATCH;
    GO
    -- dara error
    EXEC dbo.usp_T1_del @c1 = 1;
    GO
    EXEC dbo.usp_T1_del @c1 = 3;
    GO
    SELECT * FROM dbo.T1;
    SELECT * FROM dbo.T2<br/>GO
    DROP TABLE dbo.T2, dbo.T1;
    GO
    

    Este ejemplo no esta a prueba de fallo ya que es posible que se inserte una fila en el hijo en cuanto terminamos la comprobacion de existencia "IF NOT EXISTS (...)", debido a que estamos usando el nivel de aislamiento por defecto "READ COMMITTED". Es de notar que no inclui procedimiento alguno para eliminar los hijos, al igual que la sentencia para eliminar el procedimiento "drop procedure dbo.usp_T1_del".

    Espero que esta respuesta te sea de ayuda.


    AMB

    Some guidelines for posting questions...

    sábado, 5 de marzo de 2011 18:40

Todas las respuestas

  • La respuesta depende de que lado de la relacion quieres eliminar la fila.

    1 - Lado hijo (factura - cliente / detalle - producto / detalle - factura)

    En este caso solo basta con eliminar la fila.

    2 - Lado padre (factura - detalle / producto - detalle / cliente - factura)

    En este caso debes tener en cuenta que al eliminar una fila en el padre, no dejes huerfano algun hijo. Por ejemplo, si deseas eliminar un producto enotnces debes tener en cuenta si existe o no algun detalle de factura que lo referencie.

    Existen varias formas de implementar esto a nivel de SQL Server:

    2.1 - Usando restricciones referenciales en cascada como son "ON DELETE ...", las cuales te permiten cuatro tipos de accion:

        2.1.1 - NO ACTION
        2.1.1 - CASCADE
        2.1.1 - SET NULL
        2.1.1 - SET DEFAULT

    Esta forma de implementacion permite que si borras una fila en el padre, entonces con la opcion "NO ACTION" se le indica a SQL Server que no tome ninguna accion y por lo tanto si existe algun hijo referenciando al padre entonces dara error puesto que la operacion dejaria a la fila en el hijo como huerfana (apunta a un padre que no existe).  Esta opcion (NO ACTION) es la usada por defecto cuando se usa una restriccion tipo clave foranea.

    USE tempdb;
    GO
    CREATE TABLE dbo.T1 (
    c1 int NOT NULL CONSTRAINT PK_T1 PRIMARY KEY,
    c2 varchar(25) NOT NULL
    );
    GO
    CREATE TABLE dbo.T2 (
    sk int NOT NULL IDENTITY(1, 1) CONSTRAINT PK_T2 PRIMARY KEY,
    c1 int NULL
    	CONSTRAINT FK_T2_T1 REFERENCES dbo.T1(c1) ON DELETE NO ACTION,
    	--CONSTRAINT FK_T2_T1 REFERENCES dbo.T1(c1) ON DELETE SET NULL,
    	--CONSTRAINT DF_T2_c1 DEFAULT (3)
    	--CONSTRAINT FK_T2_T1 REFERENCES dbo.T1(c1) ON DELETE SET DEFAULT,
    c2 varchar(25) NOT NULL
    );
    GO
    INSERT INTO dbo.T1(c1, c2) VALUES(1, 'uno');
    INSERT INTO dbo.T1(c1, c2) VALUES(2, 'dos');
    
    INSERT INTO dbo.T2(c1, c2) VALUES(1, 'referencia a uno');
    INSERT INTO dbo.T2(c1, c2) VALUES(2, 'referencia a dos');
    
    SELECT * FROM dbo.T1;
    SELECT * FROM dbo.T2;
    
    DELETE dbo.T1
    WHERE c1 = 1;
    
    SELECT * FROM dbo.T1;
    SELECT * FROM dbo.T2;
    GO
    DROP TABLE dbo.T2, dbo.T1;
    GO
    

    Si escojemos "SET NULL", entonces la columna que se usa para referenciar al padre es puesta en NULL y terminamos con una fila huerfana pero que no apunta a nada.

    USE tempdb;
    GO
    CREATE TABLE dbo.T1 (
    c1 int NOT NULL CONSTRAINT PK_T1 PRIMARY KEY,
    c2 varchar(25) NOT NULL
    );
    GO
    CREATE TABLE dbo.T2 (
    sk int NOT NULL IDENTITY(1, 1) CONSTRAINT PK_T2 PRIMARY KEY,
    c1 int NULL
    	--CONSTRAINT FK_T2_T1 REFERENCES dbo.T1(c1) ON DELETE NO ACTION,
    	CONSTRAINT FK_T2_T1 REFERENCES dbo.T1(c1) ON DELETE SET NULL,
    	--CONSTRAINT DF_T2_c1 DEFAULT (3)
    	--CONSTRAINT FK_T2_T1 REFERENCES dbo.T1(c1) ON DELETE SET DEFAULT,
    c2 varchar(25) NOT NULL
    );
    GO
    INSERT INTO dbo.T1(c1, c2) VALUES(1, 'uno');
    INSERT INTO dbo.T1(c1, c2) VALUES(2, 'dos');
    
    INSERT INTO dbo.T2(c1, c2) VALUES(1, 'referencia a uno');
    INSERT INTO dbo.T2(c1, c2) VALUES(2, 'referencia a dos');
    
    SELECT * FROM dbo.T1;
    SELECT * FROM dbo.T2;
    
    DELETE dbo.T1
    WHERE c1 = 1;
    
    SELECT * FROM dbo.T1;
    SELECT * FROM dbo.T2;
    GO
    DROP TABLE dbo.T2, dbo.T1;
    GO
    

    Si usamos "SET DEFAULT", entonces en la columna usada para referenciar al padre se pondra un valor por defecto que se declaro durante la definicion de la tabla. Si este valor por defecto es diferente de NULL y la fila padre a la que referencia no existe, entonces obtendremos un error.

    USE tempdb;
    GO
    CREATE TABLE dbo.T1 (
    c1 int NOT NULL CONSTRAINT PK_T1 PRIMARY KEY,
    c2 varchar(25) NOT NULL
    );
    GO
    CREATE TABLE dbo.T2 (
    sk int NOT NULL IDENTITY(1, 1) CONSTRAINT PK_T2 PRIMARY KEY,
    c1 int NULL
    	--CONSTRAINT FK_T2_T1 REFERENCES dbo.T1(c1) ON DELETE NO ACTION,
    	--CONSTRAINT FK_T2_T1 REFERENCES dbo.T1(c1) ON DELETE SET NULL,
    	CONSTRAINT DF_T2_c1 DEFAULT (3)
    	CONSTRAINT FK_T2_T1 REFERENCES dbo.T1(c1) ON DELETE SET DEFAULT,
    c2 varchar(25) NOT NULL
    );
    GO
    INSERT INTO dbo.T1(c1, c2) VALUES(1, 'uno');
    INSERT INTO dbo.T1(c1, c2) VALUES(2, 'dos');
    
    INSERT INTO dbo.T2(c1, c2) VALUES(1, 'referencia a uno');
    INSERT INTO dbo.T2(c1, c2) VALUES(2, 'referencia a dos');
    
    SELECT * FROM dbo.T1;
    SELECT * FROM dbo.T2;
    
    DELETE dbo.T1
    WHERE c1 = 1;
    
    SELECT * FROM dbo.T1;
    SELECT * FROM dbo.T2;
    GO
    DROP TABLE dbo.T2, dbo.T1;
    GO
    
    

    Es de notar que estoy usando el valor por defecto (3) y que esa fila en el padre no existe, por lo que te dara un error cuando tratas de eliminar un padre con hijos. Si cambias el valor por defecto a (2), en este ejemplo, veras que los hijos del padre "c1 = 1" ahora apuntan al padre "c1 = 2".

    Por ultimo esta opcion "CASCADE" la cual eliminara todos los hijos de forma automatica en cascada. Esta opcion es util pero riesgosa puesto que si se elimina una fila padre por error, por ejemplo un cliente, entonces los hijos seran eliminados tambien (facturas).

    USE tempdb;
    GO
    CREATE TABLE dbo.T1 (
    c1 int NOT NULL CONSTRAINT PK_T1 PRIMARY KEY,
    c2 varchar(25) NOT NULL
    );
    GO
    CREATE TABLE dbo.T2 (
    sk int NOT NULL IDENTITY(1, 1) CONSTRAINT PK_T2 PRIMARY KEY,
    c1 int NULL
    	--CONSTRAINT FK_T2_T1 REFERENCES dbo.T1(c1) ON DELETE NO ACTION,
    	--CONSTRAINT FK_T2_T1 REFERENCES dbo.T1(c1) ON DELETE SET NULL,
    	--CONSTRAINT DF_T2_c1 DEFAULT (3)
    	--CONSTRAINT FK_T2_T1 REFERENCES dbo.T1(c1) ON DELETE SET DEFAULT,
    	CONSTRAINT FK_T2_T1 REFERENCES dbo.T1(c1) ON DELETE CASCADE,
    c2 varchar(25) NOT NULL
    );
    GO
    INSERT INTO dbo.T1(c1, c2) VALUES(1, 'uno');
    INSERT INTO dbo.T1(c1, c2) VALUES(2, 'dos');
    
    INSERT INTO dbo.T2(c1, c2) VALUES(1, 'referencia a uno');
    INSERT INTO dbo.T2(c1, c2) VALUES(2, 'referencia a dos');
    
    SELECT * FROM dbo.T1;
    SELECT * FROM dbo.T2;
    
    DELETE dbo.T1
    WHERE c1 = 1;
    
    SELECT * FROM dbo.T1;
    SELECT * FROM dbo.T2;
    GO
    DROP TABLE dbo.T2, dbo.T1;
    GO
    

    2.2 - La otra opcion seria usar "NO ACTION" y controlar la eliminacion de forma procedural. De esta forma puedes chequear si existen hijos o no y proceder con la eliminacion en caso deseado.

    USE tempdb;
    GO
    CREATE TABLE dbo.T1 (
    c1 int NOT NULL CONSTRAINT PK_T1 PRIMARY KEY,
    c2 varchar(25) NOT NULL
    );
    GO
    CREATE TABLE dbo.T2 (
    sk int NOT NULL IDENTITY(1, 1) CONSTRAINT PK_T2 PRIMARY KEY,
    c1 int NULL
    	CONSTRAINT FK_T2_T1 REFERENCES dbo.T1(c1) ON DELETE NO ACTION,
    	--CONSTRAINT FK_T2_T1 REFERENCES dbo.T1(c1) ON DELETE SET NULL,
    	--CONSTRAINT DF_T2_c1 DEFAULT (3)
    	--CONSTRAINT FK_T2_T1 REFERENCES dbo.T1(c1) ON DELETE SET DEFAULT,
    	--CONSTRAINT FK_T2_T1 REFERENCES dbo.T1(c1) ON DELETE CASCADE,
    c2 varchar(25) NOT NULL
    );
    GO
    INSERT INTO dbo.T1(c1, c2) VALUES(1, 'uno');
    INSERT INTO dbo.T1(c1, c2) VALUES(2, 'dos');
    INSERT INTO dbo.T1(c1, c2) VALUES(3, 'tres');
    
    INSERT INTO dbo.T2(c1, c2) VALUES(1, 'referencia a uno');
    INSERT INTO dbo.T2(c1, c2) VALUES(2, 'referencia a dos');
    
    SELECT * FROM dbo.T1;
    SELECT * FROM dbo.T2;
    GO
    CREATE PROCEDURE dbo.usp_T1_del
    @c1 int
    AS
    SET NOCOUNT ON;
    SET XACT_ABORT ON;
    
    BEGIN TRY
    	BEGIN TRANSACTION;
    	
    	IF NOT EXISTS (SELECT * FROM dbo.T2 WHERE c1 = @c1)
    		DELETE dbo.T2 WHERE c1 = @c1;
    	ELSE
    		RAISERROR ('No se puede eliminar padre %i, por que tiene hijos.', 16, 1, @c1);
    
    	DELETE dbo.T1 WHERE c1 = @c1;
    	
    	COMMIT TRANSACTION;
    	
    	RETURN 0;
    END TRY
    BEGIN CATCH
     IF @@TRANCOUNT > 0
    		ROLLBACK TRANSACTION;
    	
    	SELECT
    		ERROR_NUMBER() AS ErrorNumber
    		,ERROR_SEVERITY() AS ErrorSeverity
    		,ERROR_STATE() AS ErrorState
    		,ERROR_PROCEDURE() AS ErrorProcedure
    		,ERROR_LINE() AS ErrorLine
    		,ERROR_MESSAGE() AS ErrorMessage;
    
    	RETURN -1;
    END CATCH;
    GO
    -- dara error
    EXEC dbo.usp_T1_del @c1 = 1;
    GO
    EXEC dbo.usp_T1_del @c1 = 3;
    GO
    SELECT * FROM dbo.T1;
    SELECT * FROM dbo.T2<br/>GO
    DROP TABLE dbo.T2, dbo.T1;
    GO
    

    Este ejemplo no esta a prueba de fallo ya que es posible que se inserte una fila en el hijo en cuanto terminamos la comprobacion de existencia "IF NOT EXISTS (...)", debido a que estamos usando el nivel de aislamiento por defecto "READ COMMITTED". Es de notar que no inclui procedimiento alguno para eliminar los hijos, al igual que la sentencia para eliminar el procedimiento "drop procedure dbo.usp_T1_del".

    Espero que esta respuesta te sea de ayuda.


    AMB

    Some guidelines for posting questions...

    sábado, 5 de marzo de 2011 18:40
  • Hola. La integridad referencial, se crean, segun la logica de las aplicaciones. Y no estan para saltarselas. Planteate si las realciones entre esas tablas son las correctas. 

    No puedes "eliminar" a los "hijos", sin antes "borrar"  a los padres. Lo unico que tienes que hacer, es ir al diseño de tu tabla y activar el BORRADO EN CASCADA, hay tambien otras formas de hacerlo, segun tu versión de SQL Server, pues no indicas cual es...¿?

     

    Microsoft SQL Server proporciona integridad referencial declarativa (DRI) que permite definir restricciones de integridad de datos para una tabla, así como relaciones entre tablas, los cuales se aplican por SQL Server automáticamente en el nivel del sistema.

    SQL Server se ajusta a ANSI SQL de entrada con respecto a la integridad referencial entre columnas PrimaryKey y ForeignKey que requiere inserción, actualización y eliminación de datos en tablas relacionadas para restringirse a valores que conservar la integridad.

    ANSI SQL intermedio agrega 'acciones referenciales', que describen qué debe hacerse a valores ForeignKey dependientes cuando se actualiza o se eliminan sus correspondientes valores PrimaryKey. 

    Tedejo un link a un artículo donde describe cómo pueden implementarse eliminaciones en cascada y las actualizaciones de una forma generica para todas las versiones de SQL Server.

    En cascada eliminaciones y actualizaciones: http://support.microsoft.com/kb/142480/es

     


     Norman M. Pardell 

    ||Microsoft Certified IT Professional|| Database Administrator. Database Developer. SQL Server 2008

    sábado, 5 de marzo de 2011 21:57
  • > No puedes "eliminar" a los "hijos", sin antes "borrar"  a los padres. 

    Me inmagino que quieres decir lo contrario, no puedes borrar los padres sin antes borrar a los hijos.

     

     


    AMB

    Some guidelines for posting questions...

    domingo, 6 de marzo de 2011 0:02
  • Hunchback, Gracias, lo escribi al rebes y pude confundir.
     Norman M. Pardell 

    ||Microsoft Certified IT Professional|| Database Administrator. Database Developer. SQL Server 2008

    domingo, 6 de marzo de 2011 16:34
  • Mi versión de sql server es 2008 enterprise versión de evaluación...y gracias por sus consejos, pues activé la eliminación en cascada y eso es suficiente, porque al borrar un padre también se borran todos los registro que dependen de el.

    lunes, 30 de mayo de 2011 6:50
  • Para asegurarse de no eliminar físicamente un padre por error, creo que lo mejor sería crear una especie de eliminación lógica. por ejemplo crear un campo estado que determine si está eliminado o no. Ustedes como expertos deben saber más sobre el tema.

    lunes, 30 de mayo de 2011 6:55