none
Procedimiento almacenado: insertar id de la tabla maestro a una tabla detalle RRS feed

  • Pregunta

  • Buenos dias:

    Actualmente tengo el siguiente procedimiento almacenado

    CREATE PROCEDURE [dbo].[uspInsertarMonto]
    (@cod varchar(2))
    AS
    --DECLARE @cod varchar(2)
    
    set @cod='01'
    
    BEGIN
    
    	SET NOCOUNT ON;
    	declare @monto int
    	set @monto = (SELECT count(*) as monto FROM dbo.Ventas)
    
    	INSERT INTO dbo.Empleados
    	 (
    	   [cod],
           [nMontoNeto]
    	 )
    	 VALUES
    	 (
    	   	@cod,
    	    @monto )
    	  
    END	 

    Tengo otra tabla donde tengo que obtener el id del maestro en este caso dbo.Empleados a una tabla dbo.Empleados_detalles, osea quedaria como sigue:

    id   id_maestro

    1     1

    Si alguien sabe como hacerlo estare muy agradecido, ademas no se utilizar un rall back, y capturar errores, en el caso que si no guarda el detalle que deshaga el maestro.

    Gracias de antemano.

    jueves, 4 de mayo de 2017 14:40

Respuestas

Todas las respuestas

  • Hola,

    Lo que deseas es relacionar empleado y detalle de empleado? entonces necesitas una relación de llave foránea (FK)

    tu empleado llega con una relación uno a muchos, ya que un empleado puede tener muchos detalles, para agregar esta relación en sql utilizarías lo siguiente:

    ALTER TABLE DetalleEmpleado
    ADD CONSTRAINT FK_DetalleporEmpleado FOREIGN KEY (idEmpleado)     
    REFERENCES Empleado(idEmpleado)     

    En el ejemplo tu ya tienes creado el campo idEmpleado en la tabla Detalle y lo que haces referenciarla al idEmpleado de la tabla Empleado

    Un poco de documentación para que te orientes: Crear relaciones de clave externa

    Saludos


    Si ayudé a resolver tu consulta, no olvides marcar como respuesta y/o votar como útil.

    jueves, 4 de mayo de 2017 14:49
  • Gracias Brayan por responder:

    La FOREIGN KEY ya la tengo, relacionada, pero en el procedimiento, tengo que insertar el detalle, ademas de otras tablas y otros datos.

    Lo que no tengo claro es como insertar a la vez el maestro y el detalle, en el mismo procedimiento, porque desde el codigo fuente no hay pantallas para elegir solo para mostrar datos.

    Saludos.

    jueves, 4 de mayo de 2017 14:53
  • Hola ruyzz

    De acuerdo, entonces aquí debes utilizar Begin Transaction, un ejemplo al respecto Transacciones en SQL Server

    Deberás capturar en tu aplicación el código de empleado y enviarlo a tu procedimiento, de esa forma trabajarás insertando primero en tu tabla empleado.

    insert into Empleado(idEmpledado,...) values(@idEmpleado,...)
    
    'luego preguntas si ya existe en la tabla, puedes guardarlo en una variable
    
    declare @existe int
    set @existe = (select 1 from Empleado where idEmpleado = @idEmpleado)
    
    'preguntas si existe
    if(@existe = 1)
    begin
    ' aquí insertas tu detalle
    end

    El ejemplo es una alternativa, lógico que todo dentro de una transacción con un rollback, en el ejemplo puedes orientarte.

    Saludos


    Si ayudé a resolver tu consulta, no olvides marcar como respuesta y/o votar como útil.

    jueves, 4 de mayo de 2017 15:06
  • {...} Lo que no tengo claro es como insertar a la vez el maestro y el detalle en el mismo procedimiento, porque desde el código fuente no hay pantallas para elegir solo para mostrar datos.

    ¿El detalle se trata de una sola fila o de varias filas?, si son varias filas entonces podrías usar un parámetro de tipo table.

    Para recuperar el valor de identidad generado debes hacer uso de la función SCOPE_IDENTITY()

    BEGIN
        BEGIN TRANSACTION;  
    
        BEGIN TRY  
    	   INSERT INTO Cabecera (Col1, Col2)
    	   VALUES (@Col1, @Col2)
    
    	   DECLARE @IDGenerado int = SCOPE_IDENTITY();
    
    	   INSERT INTO Detalle (Col1, FK, Col2)
    	   VALUES (@Col1, @IDGenerado, @Col2)
        END TRY  
        BEGIN CATCH  
    	   SELECT   
    		  ERROR_NUMBER() AS ErrorNumber, ERROR_MESSAGE() AS ErrorMessage;  
    
    	   IF @@TRANCOUNT > 0  
    		  ROLLBACK TRANSACTION;  
        END CATCH;  
    
        IF @@TRANCOUNT > 0  
    	   COMMIT TRANSACTION;  
    END
    GO 


    Espero que la información proporcionada te haya sido de utilidad, quedo atento a tus comentarios.
    jueves, 4 de mayo de 2017 17:10
  • Hola Brayan:

    Para optener el id del maestro detalle hice lo siguiente:

    SELECT @idEmpleado = SCOPE_IDENTITY()

    Pero ahora hago una consulta Select con varios archivos para luego insertar en la tabla detalle

    Select * From ventas2

    Al realizar el Insert solamente inserta el ultimo registro, ¿como controlas cada registro para insertar uno por uno en la tabla de detalle?

    jueves, 4 de mayo de 2017 17:11
  • Hola Williams, gracias por responder

    el procedimiento esta excelente ademas que captura errores, pero es a como indicas:

    ¿El detalle se trata de una sola fila o de varias filas?, si son varias filas entonces podrías usar un parámetro de tipo table.

    Tengo otra tabla donde tengo que especificar en diferentes campos de detalles diferentes datos y solamente puedo insertar el ultimo registro,.

    ¿como podría hacer para controlar uno por uno y luego insertar en el detalle varias filas? No estoy claro con el parámetro de tipo table.

    jueves, 4 de mayo de 2017 17:20
  • Revisa los siguientes enlaces, son precisos en lo que debes de hacer tanto en base de datos como desde tu aplicación:

    Using Table Valued Parameters (TVP)

    Table-Valued Parameters


    Espero que la información proporcionada te haya sido de utilidad, quedo atento a tus comentarios.
    jueves, 4 de mayo de 2017 17:28
  • Hola Williams:

    En la aplicación simplemente llamo al procedimiento con un EXEC.

    BEGIN
        BEGIN TRANSACTION;  
    
        BEGIN TRY  
    	   INSERT INTO Cabecera (Col1, Col2)
    	   VALUES (@Col1, @Col2)
    
    	   DECLARE @IDGenerado int = SCOPE_IDENTITY();
               
              --NUEVA CONSULTA PARA INSERTAR
               SELECT @VENTAS2 = VENTAS2 
               FROM VENTAS2
              
               --Solamente inserta el ultimo registro 
               --de la tabla VENTAS2
    
    	   INSERT INTO Detalle (Col1, FK, Col2)
    	   VALUES (@Col1, @IDGenerado, @Col2, @VENTAS2)
    
    
        END TRY  
        BEGIN CATCH  
    	   SELECT   
    		  ERROR_NUMBER() AS ErrorNumber, ERROR_MESSAGE() AS ErrorMessage;  
    
    	   IF @@TRANCOUNT > 0  
    		  ROLLBACK TRANSACTION;  
        END CATCH;  
    
        IF @@TRANCOUNT > 0  
    	   COMMIT TRANSACTION;  
    END
    GO 

    ¿Como controlo un ciclo desde el procedimiento para que inserte uno por uno?

    Saludos.

    jueves, 4 de mayo de 2017 17:37
  • No, no necesitas enviar los detalles uno a uno, sino que los envías como un conjunto de filas a través del parámetro de tipo tabla, sólo invocas al procedimiento una sola vez. Lo que menciono es claro en los enlaces adjuntos, sólo debes adecuar a lo que necesitas.


    Espero que la información proporcionada te haya sido de utilidad, quedo atento a tus comentarios.
    jueves, 4 de mayo de 2017 17:49
  • Hola Williams:

    Quizas me ayudes con el procedimiento, envio la bd con las tablas y datos.

    CREATE procedure [dbo].[uspMaestroDetalle]
    
    AS
    
    BEGIN
    BEGIN TRANSACTION;  
    
     BEGIN TRY
    	 --SET NOCOUNT ON added to prevent extra result sets from
    	 --interfering with SELECT statements.
    	SET NOCOUNT ON;
    	
    	DECLARE @monto_neto DECIMAl(18, 0)
    	DECLARE @Id_Empleado INT
    	DECLARE @existe INT
    	DECLARE @monto_neto_det DECIMAl(18, 0)
    
    
       SET @monto_neto=(SELECT sum(v.monto) as monto_total FROM dbo.Ventas v)
     
    	
    	 --Insert statements for procedure here
    	INSERT INTO  dbo.Empleados
    	 (
    	  nombre,
    	  ventas
    	 )
    	 VALUES
    	 (
    	   	'ruyz',
    	   	@monto_neto
    	 )
    	 
    	 SELECT @Id_Empleado= SCOPE_IDENTITY()
    	 
    	 
    	 SET @existe = (SELECT 1 from dbo.Empleados WHERE idEmpleados = @Id_Empleado)
    
       IF (@existe = 1)
        BEGIN
     
    	SELECT
    		@monto_neto_det = sum(p.monto2)
    	FROM dbo.Ventas2 p 
    		
    		 
    	INSERT INTO dbo.EmpleadosDetalle
              (idEmpleado,
                montoVenta1,
                montoVenta2
               )
         VALUES(
                @Id_Empleado,
                @monto_neto,
                @monto_neto_det
    			)
         
        END
    
      END TRY
        
      BEGIN CATCH  
    	SELECT ERROR_NUMBER() AS ErrorNumber,
    		       ERROR_SEVERITY() AS ErrorSeverity,
    		       ERROR_STATE() AS ErrorState,
    		       ERROR_LINE() AS ErrorLine,
    		       ERROR_MESSAGE() AS ErrorMessage; 
    
    	   IF @@TRANCOUNT > 0  
    		  ROLLBACK TRANSACTION;  
       END CATCH;  
    
       IF @@TRANCOUNT > 0  
         COMMIT TRANSACTION; 
        
    END

    BD Empleados - Ventas

    En espera.

    Saludos.

    jueves, 4 de mayo de 2017 19:18
  • Deleted
    jueves, 4 de mayo de 2017 20:54
  • Estimado buenas tardes, he leído este bloc y he aplicado tal y como dicen los enlaces de Using TAble y Table- Value 

    el Sp desde Sql server 2014. hago la prueba desde un query Sql creando una tabla y asignandolo y me ejecuta ok y me guarda los datos en las dos tablas tanto en cabecera como en detalle.

    Pero si le envió el parámetro tipo tabla  desde mi aplicativo de vb.net  me ejecuta el sp pero en la tabla detalle que es la que contienen mi parámetro tipo tabla me lo llena con null, como que si no llegara nada desde visual.. 

    Le doy seguimiento y llega la tabla antes de poner el Command.ExecuteNonQuery(), no me genera error ni nada solo que llega nullos..

    lunes, 21 de octubre de 2019 16:13