none
Procedimiento almacenado con parámetro de salida RRS feed

  • Pregunta

  • Buenas comunidad me dirijo a ustedes hoy por una inquietud, tengo el siguiente procedimiento almacenado 

    ALTER proc [dbo].[sp_autogenerarCodigoProve]
    @codigoprov int output,
    @idempresa int
    as
    BEGIN
    BEGIN TRY
    SET TRANSACTION ISOLATION LEVEL SERIALIZABLE
    BEGIN TRANSACTION
    if(SELECT COUNT(*) FROM TablaProveedor WHERE IdEmpProveedor = @idempresa) = 0
    	BEGIN
    	if(SELECT COUNT(*) FROM TablaProveedor) = 0
    	SET @codigoprov = '1'
    	ELSE
    	SET @codigoprov = (SELECT MAX(CodNumero) FROM TablaProveedor)+1
    	END
    ELSE
    	BEGIN
    	SET @codigoprov = (SELECT MAX(CodNumero) FROM TablaProveedor WHERE IdEmpProveedor = @idempresa)+1
    	END
    COMMIT TRANSACTION
    END TRY
    BEGIN CATCH
    IF @@TRANCOUNT > 0
    ROLLBACK TRANSACTION;
    THROW;
    END CATCH
    END


    que me trae devuelta el ultimo numero de la tabla para hacer una seguidilla / números consecutivos, como especie de un código, mi problema es que quiero que esa seguidilla se base en un idempresa, a que me refiero que si el id de la empresa es 1 y el ultimo numero ingresado (de manera programática por el procedimiento almacenado) sea 4 por colocar un ejemplo, el siguiente numero que me mande sea un 5 (eso ya me lo hace) y que si mi idempresa es 3 (por ejemplo) y no tiene ningún registro el numero que me ingrese sea 1(esto no me lo hace), no se si me hice explicar, pero no me lo agarra sin importar el idempresa siempre me trae el ultimo. El CodNumero es una columna de mi TablaProveedor de tipo INT

    Lo llamo asi desde C#

    capa datos:

    public int GenerarCodigo2()
            {
                using (var conexion = ObtenerConexion())
                {
                    conexion.Open();
                    using (var comando = new SqlCommand())
                    {
                        comando.Connection = conexion;
                        comando.CommandText = "sp_autogenerarCodigoProve";              
                        SqlParameter param = new SqlParameter("@codigoprov", SqlDbType.Int);
                        param.Direction = ParameterDirection.Output;
                        comando.CommandType = CommandType.StoredProcedure;
                        comando.Parameters.AddWithValue("@idempresa", IdEmpresa);
                        comando.Parameters.Add(param);
                        comando.ExecuteNonQuery();                                                 
                        var result = comando.Parameters["@codigoprov"].Value;                                       
                        return Convert.ToInt32(result);
                    }
                }
            }

    capa negocio

    public string GenerarCodigo(string idempresa)
            {
                var codigo = dProveedor.GenerarCodigo2();
                dProveedor.IdEmpresa = Convert.ToInt32(idempresa);
                return codigo;
            }


    capa presentacion:

    esto va en mi boton guardar, junto con las variable de mi procedimiento almacenado de guardar

    var result = mProveedor.GenerarCodigo(idempresa);

    el idempresa lo traigo asi:

    string idempresa = Convert.ToString(UsuarioLoginCache.IdEmpresa);
    y se lo paso a la función

    martes, 17 de marzo de 2020 21:59

Todas las respuestas

  • Puedes simplificar muchísimo el procedimiento.

    Para empezar, puedes evitar la transacción puesto que en el procedimiento solo lees el siguiente valor pero no lo grabas, así que la transacción es superflua. Y luego, puedes simplemente leer el "max" y si el dato no existe el max devuelve null, que puedes convertir en un cero usando IsNull o Coalesce.

    SET @codigoprov = (SELECT coalesce(MAX(CodNumero), 0) FROM TablaProveedor WHERE IdEmpProveedor = @idempresa)+1


    Ya está, esa línea sola ya hace todo el trabajo de tu procedimiento y puedes borrar todo el resto. Y no tiene el error de que falta un "where" en la segunda y tercera Select que hace que no funcione bien si no hay dato para esa empresa.

    • Marcado como respuesta NathalyChR miércoles, 18 de marzo de 2020 12:59
    • Desmarcado como respuesta NathalyChR miércoles, 18 de marzo de 2020 12:59
    miércoles, 18 de marzo de 2020 7:19
    Moderador
  • hola

    Algunos comentarios

    - Porque usas transacciones en el procedure cuando solo veo que defines SELECT, no estas cambiando nada en los registros no necesitas transacciones, puedes quitarlas

    -En la tabla proveedor puedes tener mas de un registro para la empresa? la columna codNumero es la key de la tabla de proveedores?

    Podrias solo definir

    ALTER proc [dbo].[sp_autogenerarCodigoProve]
    @idempresa int
    as
    BEGIN
    
    	SELECT ISNULL(MAX(CodNumero),0) FROM TablaProveedor WHERE IdEmpProveedor = @idempresa
    
    END


    usando el ExecuteScalar() para tomar el valor

    public int GenerarCodigo2(int IdEmpresa)
    {
    	using (var conexion = ObtenerConexion())
    	{
    		conexion.Open();
    		using (var comando = new SqlCommand("sp_autogenerarCodigoProve", conexion))
    		{           
    			comando.CommandType = CommandType.StoredProcedure;
    			comando.Parameters.AddWithValue("@idempresa", IdEmpresa);
                     
    			return Convert.ToInt32(comando.ExecuteScalar());
    		}
    	}
    }

    asi de simple

    saludos


    Leandro Tuttini

    Blog
    MVP Profile
    Buenos Aires
    Argentina

    miércoles, 18 de marzo de 2020 13:27
  • >>>>>>Porque usas transacciones en el procedure cuando solo veo que defines SELECT, no estas cambiando nada en los registros no necesitas transacciones, puedes quitarlas

    es por si insertan en la misma empresa al mismo tiempo, no se si las transacciones evitan eso

    >>>>>>En la tabla proveedor puedes tener mas de un registro para la empresa? la columna codNumero es la key de la tabla de proveedores?

    en la tablaproveedor estan todos los registros de las diferentes empresas por eso quiero que guarde el siguiente numero dependiendo de la id que si la empresa con id 1 su ultimo numero de registro es 3 ve guarde el 4 en la tabla y si la empresa con id 2 no tiene registro, entonces me guarde un 1 ya que es el primer registro que se va a guardar. Y no, el codNumero no es mi ID es un entero que puede tener valores duplicado por decirlo asi porque es dependiendo de la empresa

    Como lo tengo guardar pero no me agarra el id, solo me agarra el MAX de la tabla completa y quiero que sea por id que me agarre el MAX dependiendo del ID

    miércoles, 18 de marzo de 2020 13:40
  • Pero no me agarra por Id no se si con tu respuesta si se agarra, pueden haber varias insercciones
    miércoles, 18 de marzo de 2020 13:41
  • hola

    >>es por si insertan en la misma empresa al mismo tiempo, no se si las transacciones evitan eso

    pero la transaccion que estas definiendo solo tiene el ambito de ese procedure y alli no estas realizando nunguna actualizacion o insert en ninguna tabla

    No digo que no uses transacciones, pero alli como lo defines no sirve de nada porque el valor que obtienes lo estas usando en otro sitio donde si realizar el insert, es alli donde debes definir la transaccion

    la transaccion con un select no aplica

    >>codNumero no es mi ID es un entero que puede tener valores duplicado por decirlo asi porque es dependiendo de la empresa

    no entendi, no es id es entero, eso que significa? id no es un tipo de datos, es si fue marcado como key de la tabla

    puede tener un campo que sea int y key al mismo tiempo

    >>Como lo tengo guardar pero no me agarra el id, solo me agarra el MAX de la tabla completa y quiero que sea por id que me agarre el MAX dependiendo del ID

    cuando tomas el max que haces con ese dato?

    - realizas un UPDATE actualizando el CodNumero para la empresa en la tabla proveedores

    - realizas un INSERT creando un nuevo registro con ese nuevo valor que obtuviste en el max

    por lo general lo secuenciales se usan para generar nuevos registros

    si tienes registro unico por empresa y ese codnumero es un valor que vas a incrementar no se usa ningun max ni nada, solo se recupera el valor usando

    SELECT ISNULL(CodNumero,0) FROM TablaProveedor WHERE IdEmpProveedor = @idempresa

    y a ese valor le sumas uno y luego realizas el UPDATE

    UPDATE TablaProveedor SET CodNumero = @valor WHERE IdEmpProveedor = @idempresa


    imaginando que IdEmpProveedor es la key de la tabla

    saludos


    Leandro Tuttini

    Blog
    MVP Profile
    Buenos Aires
    Argentina

    miércoles, 18 de marzo de 2020 14:26
  • >>>>no entendi, no es id es entero, eso que significa? id no es un tipo de datos, es si fue marcado como key de la tabla

    ok me explico, en mi tabla proveedor tengo un IdProveedor que es la key de la tabla, mi codNumero es simplemente un entero, que se le va a sumar uno, por eso el SELECT  con el COUNT que si no hay una registro le asigne 1 y de ahí le va sumando, pero quiero que esa suma sea por IdEmpresa que si mi empresa con id 1 tiene 5 registros el próximo que se inserte me traiga el numero 6, y si mi empresa con id 4 no tiene ningún registro osea el COUNT es = 0 me devuelva un 1 y así me va a ir sumando dependiendo del IdEmpresa, pero como lo tengo no lo hace, siempre me va a agarrar el MAX de la tabla, entonces siguiendo con el ejemplo si mi empresa con Id 4 no tiene ningún registro me guarda en vez de 1 un 6 (porque el anterior es 5) mi idempresa viene de otra tabla donde se guardan los datos de la empresa. No se si ahora si me explique mejor.

    >>>realizas un INSERT creando un nuevo registro con ese nuevo valor que obtuviste en el max

    Si, agarro ese CodNumero y lo guardo en mi tabla proveedor, porque es un código que creo con la palabra PROV pero la palabra la tengo en una columna y el numero en otra

    >>si tienes registro unico por empresa y ese codnumero es un valor que vas a incrementar no se usa ningun max ni nada, solo se recupera el valor usando

    Esto no lo entendi, en mi tabla proveedor están los proveedores de todas las empresa, pero yo los muestro dependiendo de id de la empresa, por eso mi pregunta de como agarro el MAX de la columna codNumero dependiendo del Id de la empresa

    miércoles, 18 de marzo de 2020 14:52
  • hola

    >>mi tabla proveedor tengo un IdProveedor que es la key de la tabla...pero quiero que esa suma sea por IdEmpresa que si mi empresa

    pero como se relaciona el proveedor con la empresa?

    podrias explicar la estructura de las tablas porque la verdad esta muy raro como lo diseñas o algo no esta teniendo sentido

    sera algo asi

    TablaProveedor (tabla)
    IdProveedor  PK
    IdEmpProveedor  FK
    CodNumero
    
    ...otras columnas

    PK primary key

    FK foreing key, es una columna que se relaciona con la tabla de empresas

    el id empresa se relaciona uno a muchos con la tabla de empresas ?

    >>en mi tabla proveedor están los proveedores de todas las empresa

    Como se relacionan proveedores con empresas ? es una relacion uno a muchos o muchos a muchos

    saludos


    Leandro Tuttini

    Blog
    MVP Profile
    Buenos Aires
    Argentina

    miércoles, 18 de marzo de 2020 18:42
  • >>>>>pero como se relaciona el proveedor con la empresa?

    Una empresa puede tener muchos proveedores, la empresa que se registre va a tener un id y cuando se registra un proveedor va a agarrar ese id de empresa y se va a guardar en una columna de mi tabla proveedor
    Idproveedor, nombreProveedor,letraProve,CodNumero...,IdEmpresa... esto para que solo muestre a los proveedores asociado a ese idEmpresa 

    el proveedor va a tener un codigo, generado automaticamente desde el procedimiento almacenado, si la empresa no tiene ningun proveedor registrado y se registra 1, el codigo deberia de empezar en 1, si se registra otro sigue con el 2... Asi sucesivamente, mi problema es que en la tabla me esta agarrando el MAX de toda la tabla y yo quiero que me filtre por la Columna IdEmpresa, y que me agarre el MAX dependiendo del IdEmpresa.

    Edito:

    ejecute el procedimiento almacenado directamente en sql y si me agarra el ultimo id dependiendo del IdEmpresa, entonces mi problema esta en que no esta recibiendo el parametro idempresa cuando se lo mando a la función:

    public int GenerarCodigo2()
            {
                using (var conexion = ObtenerConexion())
                {
                    conexion.Open();
                    using (var comando = new SqlCommand())
                    {
                        comando.Connection = conexion;
                        comando.CommandText = "sp_autogenerarCodigoProve";              
                        SqlParameter param = new SqlParameter("@codigoprov", SqlDbType.Int);
                        param.Direction = ParameterDirection.Output;
                        comando.CommandType = CommandType.StoredProcedure;
                        comando.Parameters.AddWithValue("@idempresa", IdEmpresa);
                        comando.Parameters.Add(param);
                        comando.ExecuteNonQuery();                                                 
                        var result = comando.Parameters["@codigoprov"].Value;                                       
                        return Convert.ToInt32(result);
                    }
                }
            }


    • Editado NathalyChR miércoles, 18 de marzo de 2020 21:24
    miércoles, 18 de marzo de 2020 21:11
  • hola

    >>la empresa que se registre va a tener un id y cuando se registra un proveedor va a agarrar ese id de empresa y se va a guardar en una columna de mi tabla proveedor

    bien, eso es una relacion uno a muchos

    >>si la empresa no tiene ningun proveedor registrado y se registra 1, el codigo deberia de empezar en 1, si se registra otro sigue con el 2

    Pero entonces CodNumero deberia estar en la tabla de Empresas, no en el proveedor

    Un proveedor solo le puede pertener a una unica empresa, deberias analizar el sentido de la relacion, no se que base de datos utilizas, pero si es Sql Server intenta crearte un diagrama para poner las tablas y ver como se relacionan por estas columnas de idProveedor que tienes en la tabla de proveedores

    Ademas esa columna no la necesitas porque si relacionas las tablas puede calcular la cantidad de proveedores que tiene una empresa usando la consulta

    SELECT COUNT(*) As CantProveedores
    FROM Proveedores 
    WHERE idEmpresa =  @idempresa

    con eso tienes la cantidad de proveedores relacionado con la empresa, no necesitas llevar un campo con ese dato porque lo puedes calcular cuando lo requieras

    saludos


    Leandro Tuttini

    Blog
    MVP Profile
    Buenos Aires
    Argentina

    miércoles, 18 de marzo de 2020 22:13