none
Error al convertir el tipo de datos nvarchar a numeric.

    Pregunta

  • Buen dia, aqui una vez más, esta es mi sigueinte consulta:

    desde un formulario, luego de hacer unos calculos ( subtotal, total , montoIGV)  y estos los quiero guardar en una tabla donde subtotal, total , son de tipo numeric, pero al momento de hacer la insercion me sale el siguiten error:

    Error al convertir el tipo de datos nvarchar a numeric.

    el código que ejecuto es el siguiente.
    A la espera de sus respuestas

    Saludos Cordiales a todos.
    DLB

      Dim Igv As Double = 0.19

            'Calcular subtotal

            txtFacSubtotal.Text = FormatNumber(Val(txtPorcentaje.Text) * CDbl(txtMonto.Text), 2)
            'Calcular Igv
            txtFacIGV.Text = FormatNumber(Igv * CDbl(txtFacSubtotal.Text), 2)
            'Calcular Total
            txtFacTotal.Text = FormatNumber(CDbl(txtFacSubtotal.Text) + CDbl(txtFacIGV.Text), 2)
            lblvalGarantia.Text = FormatPercent(garantia, 0)
            txtMonGarantia.Text = FormatNumber(garantia * CDbl(txtFacTotal.Text), 2)
            txtMontoCobrar.Text = FormatNumber((1 - garantia) * CDbl(txtFacTotal.Text), 2)
            Dim sql As String = "insert into detallefac(porcentaje,numSerie,numCorrela,subtotal,total,montogarant,montoCobrar) " & _
            "values (@porcentaje,@numserie,@numcorrelativo,@subtotal,@total,@montogarant,@montoCobrar)"
            Dim sentencia As New SqlCommand(sql, con)
            With sentencia
                .Parameters.AddWithValue("@porcentaje", txtPorcentaje.Text)
                .Parameters.AddWithValue("@numserie", txtnumSer.Text)
                .Parameters.AddWithValue("@numcorrelativo", txtnumCorr.Text)
                .Parameters.AddWithValue("@subtotal", txtFacSubtotal.Text)
                .Parameters.AddWithValue("@total", txtFacTotal.Text)
                .Parameters.AddWithValue("@montogarant", txtMonGarantia.Text)
                .Parameters.AddWithValue("@montoCobrar", txtMontoCobrar.Text)


            End With
            abrirconexion()
            sentencia.ExecuteNonQuery()
            sentencia.Dispose()

    • Editado danielchl domingo, 30 de mayo de 2010 20:37 mejor vizualizacion del codigo
    domingo, 30 de mayo de 2010 20:34

Respuestas

  • Sigue la ejecución con el debugger hasta encontrar la sentencia que da error y verifica cuál es el valor que le llega y a qué se está convirtiendo. Por ejemplo, puede que tengas problemas si el sistema está configurado para usar coma decimal y punto de miles, y los números los tecleas al contrario (punto decimal y coma de miles) o viceversa. Comprueba cuál es el valor que de verdad recuperas en la variable de tipo decimal, y a continuación cerciórate de que cabe en el campo de la base de datos en el que lo intentas meter. Por ejemplo, si el monto vale 1000 y lo intentas meter en un numeric(5,2) se desbordará, porque en ese campo sólo cabe 999,99.

    • Marcado como respuesta danielchl lunes, 31 de mayo de 2010 21:12
    lunes, 31 de mayo de 2010 20:41

Todas las respuestas

  • Estás usando el AddWithValue pasándole un valor de tipo String en todos los casos. Esto hace que ADO.NET genere un parámetro de tipo nvarchar para pasarle el valor a la sentencia. Si los campos de la tabla son de tipo numeric, se producen errores al realizar las conversiones.

    Lo correcto es que el tipo de dato se lo indiques al construir cada parámetro para el SqlCommand, o al menos, si quieres simplificar el código mediante el AddWithValue, pasarle un tipo correcto a esta función para que pueda deducir correctamente el tipo del parámetro. Por ejemplo, para el campo "total", que presumiblemente será numérico, puedes hacer esto:

    Dim dTotal as Decimal = Decimal.Parse(txtFacTotal.Text)
    .Parameters.AddWithValue("@subtotal", dTotal)

    y lo mismo debes hacer con todos los demás parámetros que sean numéricos.

    Y aprovecho para mencionarte otra cosa: Con los datos que sean de longitud variable, tales como los varchar o nvarchar, no deberías usar el .AddWithValue. Este métdo genera un parámetro de longitud distinta por cada texto que le pasas que tiene una longitud distinta. Esto hace que el servidor considere cada una de las sentencias distinta, en lugar de considerar que le vuelve a llegar la misma pero con distintos parámetros. La consecuencia es que se poluciona el caché de procedimientos en el servidor, guardando más sentencias de las necesarias, y perjudicando por tanto al rendimiento del SqlServer.

     

     

    domingo, 30 de mayo de 2010 21:14
  • Hola Alberto, gracias por la ayuda, un favor, me podrias explicar no entendi muy bien lo que explicaste:

    "Y aprovecho para mencionarte otra cosa: Con los datos que sean de longitud variable, tales como los varchar o nvarchar, no deberías usar el .AddWithValue. Este métdo genera un parámetro de longitud distinta por cada texto que le pasas que tiene una longitud distinta. Esto hace que el servidor considere cada una de las sentencias distinta, en lugar de considerar que le vuelve a llegar la misma pero con distintos parámetros. La consecuencia es que se poluciona el caché de procedimientos en el servidor, guardando más sentencias de las necesarias, y perjudicando por tanto al rendimiento del SqlServer."

     

    gracias

    lunes, 31 de mayo de 2010 6:12
  • Ahora tengo otro problema, luego de realizar la sugerencia de Alberto:

    " Dim dTotal as Decimal = Decimal.Parse(txtFacTotal.Text)
    .Parameters.AddWithValue("@subtotal", dTotal) "

    me sale el siguiente error:

    Error de desbordamiento aritmético al convertir numeric al tipo de datos numeric.

    El codigo que estoy ejecutando es el siguiente:

    Dim Igv As Double = 0.19

            'Calcular subtotal

            txtFacSubtotal.Text = FormatNumber(Val(txtPorcentaje.Text) * CDbl(txtMonto.Text), 2)
            'Calcular Igv
            txtFacIGV.Text = FormatNumber(Igv * CDbl(txtFacSubtotal.Text), 2)
            'Calcular Total
            txtFacTotal.Text = FormatNumber(CDbl(txtFacSubtotal.Text) + CDbl(txtFacIGV.Text), 2)
            lblvalGarantia.Text = FormatPercent(garantia, 0)
            txtMonGarantia.Text = FormatNumber(garantia * CDbl(txtFacTotal.Text), 2)
            txtMontoCobrar.Text = FormatNumber((1 - garantia) * CDbl(txtFacTotal.Text), 2)
            Dim sql As String = "insert into detallefac(porcentaje,numSerie,numCorrela,subtotal,total,montogarant,montoCobrar) " & _
            "values (@porcentaje,@numserie,@numcorrelativo,@subtotal,@total,@montogarant,@montoCobrar)"
            Dim sentencia As New SqlCommand(sql, con)
            With sentencia
                Dim dporcentaje As Decimal = Decimal.Parse(txtPorcentaje.Text)
                .Parameters.AddWithValue("@porcentaje", dporcentaje)
      ''este es de tipo varchar por eso no modifico
            
                .Parameters.AddWithValue("@numserie", txtnumSer.Text)
      ''este es de tipo varchar por eso no modifico
             
                .Parameters.AddWithValue("@numcorrelativo", txtnumCorr.Text)
                Dim dsubtotal As Decimal = Decimal.Parse(txtFacSubtotal.Text)
                .Parameters.AddWithValue("@subtotal", dsubtotal)
                Dim dTotal As Decimal = Decimal.Parse(txtFacTotal.Text)
                .Parameters.AddWithValue("@total", dTotal)
                Dim dmontgarant As Decimal = Decimal.Parse(txtMonGarantia.Text)
                .Parameters.AddWithValue("@montogarant", dmontgarant)
                Dim dMontCobro As Decimal = Decimal.Parse(txtMontoCobrar.Text)
                .Parameters.AddWithValue("@montoCobrar", dMontCobro)


            End With
            abrirconexion()
            sentencia.ExecuteNonQuery()


    lunes, 31 de mayo de 2010 6:25
  • Bien, vayamos por pasos.

    ¿Qué hace SQL Server cuando le llega una sentencia SQL? Tiene que analizar el texto, deducir qué hace, y elegir una estrategia óptima para resolverla (qué índices usar, qué forma de hacer los Joins, etc.). Este proceso es costoso. Para reducir el coste, una vez analizada y optimizada una sentencia, se guarda en un caché para no tener que volver a procesarla si el programa cliente vuelve a enviar la misma sentencia.

    La sentencia que se guarda en el caché incluye los parámetros. Por ejemplo, si es un "Select * from mitabla where campo=@valor", la sentencia se considera la misma aunque se reciba un nuevo valor para el @valor. El tipo de parámetro se guarda junto con la sentencia, por ejemplo, si @valor es un varchar(10), y luego llega otra sentencia con un @valor que es un varchar(15), se consideran sentencias distintas y ocupan dos entradas en el cache.

    Ahora pasemos a tu programa cliente. ¿Qué hace el AddWithValue? Construye un parámetro deduciendo su tipo a partir del valor que le pasas en el segundo argumento. Por ejemplo, si haces esto:

    comando.Paramenters.AddWithValue("@valor", "pepe")

    lo que se genera es esto:

    Dim param as New SqlPArameter("@valor", SqlDbType.NVarchar, 4)
    param.Value = "pepe"
    comando.Parameters.Add(param)

    Como puedes ver, ha generado un NVarchar(4) deduciéndolo a partir de que le has pasado "pepe", que es una cadena Unicode de 4 caracteres.

    Si esto lo repites varias veces con distintos valores, se va generando cada vez una sentencia con un parámetro distinto, y el servidor la considera diferente y vuelve a optimizarla y ocupa una nueva entrada en el caché. Por eso los parámetros de longitud variable, como los nvarchar, conviene declararlos con la sintaxis "larga" en lugar de dejar que se autodeclaren mediante el AddWithValue.

     

    lunes, 31 de mayo de 2010 6:29
  • Ahora tengo otro problema, luego de realizar la sugerencia de Alberto:

    " Dim dTotal as Decimal = Decimal.Parse(txtFacTotal.Text)
    .Parameters.AddWithValue("@subtotal", dTotal) "

    me sale el siguiente error:

    Error de desbordamiento aritmético al convertir numeric al tipo de datos numeric.

    El codigo que estoy ejecutando es el siguiente:

    Dim Igv As Double = 0.19

            'Calcular subtotal

            txtFacSubtotal.Text = FormatNumber(Val(txtPorcentaje.Text) * CDbl(txtMonto.Text), 2)
            'Calcular Igv
            txtFacIGV.Text = FormatNumber(Igv * CDbl(txtFacSubtotal.Text), 2)
            'Calcular Total
            txtFacTotal.Text = FormatNumber(CDbl(txtFacSubtotal.Text) + CDbl(txtFacIGV.Text), 2)
            lblvalGarantia.Text = FormatPercent(garantia, 0)
            txtMonGarantia.Text = FormatNumber(garantia * CDbl(txtFacTotal.Text), 2)
            txtMontoCobrar.Text = FormatNumber((1 - garantia) * CDbl(txtFacTotal.Text), 2)
            Dim sql As String = "insert into detallefac(porcentaje,numSerie,numCorrela,subtotal,total,montogarant,montoCobrar) " & _
            "values (@porcentaje,@numserie,@numcorrelativo,@subtotal,@total,@montogarant,@montoCobrar)"
            Dim sentencia As New SqlCommand(sql, con)
            With sentencia
                Dim dporcentaje As Decimal = Decimal.Parse(txtPorcentaje.Text)
                .Parameters.AddWithValue("@porcentaje", dporcentaje)
      ''este es de tipo varchar por eso no modifico
            
                .Parameters.AddWithValue("@numserie", txtnumSer.Text)
      ''este es de tipo varchar por eso no modifico
             
                .Parameters.AddWithValue("@numcorrelativo", txtnumCorr.Text)
                Dim dsubtotal As Decimal = Decimal.Parse(txtFacSubtotal.Text)
                .Parameters.AddWithValue("@subtotal", dsubtotal)
                Dim dTotal As Decimal = Decimal.Parse(txtFacTotal.Text)
                .Parameters.AddWithValue("@total", dTotal)
                Dim dmontgarant As Decimal = Decimal.Parse(txtMonGarantia.Text)
                .Parameters.AddWithValue("@montogarant", dmontgarant)
                Dim dMontCobro As Decimal = Decimal.Parse(txtMontoCobrar.Text)
                .Parameters.AddWithValue("@montoCobrar", dMontCobro)


            End With
            abrirconexion()
            sentencia.ExecuteNonQuery()

    lunes, 31 de mayo de 2010 19:37
  • Sigue la ejecución con el debugger hasta encontrar la sentencia que da error y verifica cuál es el valor que le llega y a qué se está convirtiendo. Por ejemplo, puede que tengas problemas si el sistema está configurado para usar coma decimal y punto de miles, y los números los tecleas al contrario (punto decimal y coma de miles) o viceversa. Comprueba cuál es el valor que de verdad recuperas en la variable de tipo decimal, y a continuación cerciórate de que cabe en el campo de la base de datos en el que lo intentas meter. Por ejemplo, si el monto vale 1000 y lo intentas meter en un numeric(5,2) se desbordará, porque en ese campo sólo cabe 999,99.

    • Marcado como respuesta danielchl lunes, 31 de mayo de 2010 21:12
    lunes, 31 de mayo de 2010 20:41
  • Excelente, ahora si me funciono , tenias toda la razon estaba considerando mal la cantidad de digitos. Grcias.
    lunes, 31 de mayo de 2010 21:12