none
Ayuda para borrar en cascada (3 tablas) RRS feed

  • Pregunta

  • Saludos amigos...


    Solicito de su apoyo, para llevar a cabo un borrado a 3 tablas, para lo cual utilizo un SP el cual me notifica problema de llaves foráneas, si ejecuto la primera ves el SP, pero a la segunda pasada procede a realizar normalmente el borrado sin notificar ningún error, les comparto el diagrama:



    Aquí unos registros que tengo:

    Borro primero la información de tabla grupos, posteriormente elimino la de tutorados y finalmente tutor, así de simple, pero no me permite en la primer corrida, me envia problemas de llaves foraneas, es hasta la segunda pasada que lo hace sin errores, no se a que se deba, talves no lo estoy haciendo bien...

    	declare @cve_gpo as varchar(3) = '162'
    	declare @cve_mat as varchar(5) = '01113'
    	declare @cve_carrera as varchar(5) = '013'
    	declare @crpe as varchar(5) = '08685'
    	declare @id_gpo as integer = 25
    	declare @tid_tutor as integer = (SELECT id FROM [Tutorias].[dbo].[tutor] where crpe = @crpe)
    	print @tid_tutor
    	delete FROM [Tutorias].[dbo].[grupos] where id = @id_gpo (primero borro el grupo)
    
    	update [kardex].[dbo].[CpoTutorias] set iestado = 0 (acualizo en otra BD)
    		from [Tutorias].[dbo].[tutorado] t
    		where ([kardex].[dbo].[CpoTutorias].cve_unica = t.cve_unica and t.id_grupos = @id_gpo and t.cve_carrera = @cve_carrera)
    
    	delete FROM [Tutorias].[dbo].[tutorado] where id_grupos = @id_gpo (borro en tutorado)	
    
    	delete FROM [Tutorias].[dbo].[tutor] where id = @tid_tutor (finalmente tutor)
    
    	update [kardex].[dbo].[GpoTutorias] set [iestado] = 0 (actualizo en otra BD)
    		where cve_gpo = @cve_gpo and cve_mat = @cve_mat and cve_maes = @crpe  and cve_car = @cve_carrera
    			and iestado = 1

    Agradezco de su apoyo. La verdad no se que pueda estar haciendo mal.


    miércoles, 5 de febrero de 2020 3:53

Respuestas

  • Hola Marco Bueno:

    Prueba esto:

    SET XACT_ABORT ON
    SET NOCOUNT ON
    
    BEGIN TRAN
    BEGIN TRY
    
    	declare @cve_gpo as varchar(3) = '162'
    	declare @cve_mat as varchar(5) = '01113'
    	declare @cve_carrera as varchar(5) = '013'
    	declare @crpe as varchar(5) = '08685'
    	declare @id_gpo as integer = 25
    	declare @tid_tutor as integer = (SELECT id FROM [Tutorias].[dbo].[tutor] where crpe = @crpe)
    	print @tid_tutor
    
    	update [kardex].[dbo].[CpoTutorias] set iestado = 0 (acualizo en otra BD)
    		from [Tutorias].[dbo].[tutorado] t
    		where ([kardex].[dbo].[CpoTutorias].cve_unica = t.cve_unica and t.id_grupos = @id_gpo and t.cve_carrera = @cve_carrera)
    
    	update [kardex].[dbo].[GpoTutorias] set [iestado] = 0 (actualizo en otra BD)
    		where cve_gpo = @cve_gpo and cve_mat = @cve_mat and cve_maes = @crpe  and cve_car = @cve_carrera
    			and iestado = 1
    
    	delete FROM [Tutorias].[dbo].[tutor] where id = @tid_tutor --(Primer tutor)
    	
    	delete FROM [Tutorias].[dbo].[grupos] where id = @id_gpo --(luego grupo)
    
    	delete FROM [Tutorias].[dbo].[tutorado] where id_grupos = @id_gpo --(luego tutorado)	
    
    	COMMIT TRAN;
    END TRY
    BEGIN CATCH
    	IF (@@TRANCOUNT > 0)
    		ROLLBACK TRAN;
    
    	DECLARE @ErrorMessage NVARCHAR(4000);  
        DECLARE @ErrorSeverity INT;  
        DECLARE @ErrorState INT;  
      
        SELECT   
            @ErrorMessage = ERROR_MESSAGE(),  
            @ErrorSeverity = ERROR_SEVERITY(),  
            @ErrorState = ERROR_STATE();  
      
        -- Use RAISERROR inside the CATCH block to return error  
        -- information about the original error that caused  
        -- execution to jump to the CATCH block.  
        RAISERROR (@ErrorMessage, -- Message text.  
                   @ErrorSeverity, -- Severity.  
                   @ErrorState -- State.  
                   );  
    END CATCH

    Si borras primero el tutor, nada le impide a la tabla grupos borrarse, puesto que su registro al que estaba asociado, esta borrado.

    Si borras después el grupo, nada le impide a su tabla tutorado borrarse, ya que el grupo esta eliminado.

    Envuelves todo el código en una sola transacción y si se ha podido efectuar correctamente, se confirma. Caso contrario se deshace entera, y así no quedan datos huéfanos o inconexos.

    Otra opción, es modificar las foreign keys, para que sean ellas solas las que borren los registros.

    foreign key on delete cascade.

    https://www.sqlshack.com/es/eliminar-en-cascada-y-actualizar-cascada-en-la-clave-externa-de-sql-server/

    • Propuesto como respuesta Diana AcuñaModerator miércoles, 5 de febrero de 2020 15:32
    • Marcado como respuesta Marco Bueno miércoles, 5 de febrero de 2020 19:57
    miércoles, 5 de febrero de 2020 4:43

Todas las respuestas

  • Hola Marco Bueno:

    Prueba esto:

    SET XACT_ABORT ON
    SET NOCOUNT ON
    
    BEGIN TRAN
    BEGIN TRY
    
    	declare @cve_gpo as varchar(3) = '162'
    	declare @cve_mat as varchar(5) = '01113'
    	declare @cve_carrera as varchar(5) = '013'
    	declare @crpe as varchar(5) = '08685'
    	declare @id_gpo as integer = 25
    	declare @tid_tutor as integer = (SELECT id FROM [Tutorias].[dbo].[tutor] where crpe = @crpe)
    	print @tid_tutor
    
    	update [kardex].[dbo].[CpoTutorias] set iestado = 0 (acualizo en otra BD)
    		from [Tutorias].[dbo].[tutorado] t
    		where ([kardex].[dbo].[CpoTutorias].cve_unica = t.cve_unica and t.id_grupos = @id_gpo and t.cve_carrera = @cve_carrera)
    
    	update [kardex].[dbo].[GpoTutorias] set [iestado] = 0 (actualizo en otra BD)
    		where cve_gpo = @cve_gpo and cve_mat = @cve_mat and cve_maes = @crpe  and cve_car = @cve_carrera
    			and iestado = 1
    
    	delete FROM [Tutorias].[dbo].[tutor] where id = @tid_tutor --(Primer tutor)
    	
    	delete FROM [Tutorias].[dbo].[grupos] where id = @id_gpo --(luego grupo)
    
    	delete FROM [Tutorias].[dbo].[tutorado] where id_grupos = @id_gpo --(luego tutorado)	
    
    	COMMIT TRAN;
    END TRY
    BEGIN CATCH
    	IF (@@TRANCOUNT > 0)
    		ROLLBACK TRAN;
    
    	DECLARE @ErrorMessage NVARCHAR(4000);  
        DECLARE @ErrorSeverity INT;  
        DECLARE @ErrorState INT;  
      
        SELECT   
            @ErrorMessage = ERROR_MESSAGE(),  
            @ErrorSeverity = ERROR_SEVERITY(),  
            @ErrorState = ERROR_STATE();  
      
        -- Use RAISERROR inside the CATCH block to return error  
        -- information about the original error that caused  
        -- execution to jump to the CATCH block.  
        RAISERROR (@ErrorMessage, -- Message text.  
                   @ErrorSeverity, -- Severity.  
                   @ErrorState -- State.  
                   );  
    END CATCH

    Si borras primero el tutor, nada le impide a la tabla grupos borrarse, puesto que su registro al que estaba asociado, esta borrado.

    Si borras después el grupo, nada le impide a su tabla tutorado borrarse, ya que el grupo esta eliminado.

    Envuelves todo el código en una sola transacción y si se ha podido efectuar correctamente, se confirma. Caso contrario se deshace entera, y así no quedan datos huéfanos o inconexos.

    Otra opción, es modificar las foreign keys, para que sean ellas solas las que borren los registros.

    foreign key on delete cascade.

    https://www.sqlshack.com/es/eliminar-en-cascada-y-actualizar-cascada-en-la-clave-externa-de-sql-server/

    • Propuesto como respuesta Diana AcuñaModerator miércoles, 5 de febrero de 2020 15:32
    • Marcado como respuesta Marco Bueno miércoles, 5 de febrero de 2020 19:57
    miércoles, 5 de febrero de 2020 4:43
  • Gracias Javi Fernández

    Me distes un buen tip, lamentablemente no me fue funcional, pero me ha sido de base para idear una nueva perspectiva de ese modelo, por lo que a los tutores a los cuales les pertenecían los grupos, lleve a cavo la relación de que a los grupos les pertenecen los tutores y lleve a cabo la actualización, y llame al SP y sin problema alguno se ejecuto.

    Te agradezco amigo.

    miércoles, 5 de febrero de 2020 19:57