none
Error al consolidar unas tablas en sql compact.

    Pregunta

  • Hola a todos:

    Tengo el caso curioso que se produce al consolidar las empresas de la tabla "Balances" (A01. A02) en una tercera (A03), las cuales los que hacen es sumar la tabla A01 y A02 en la tercera A03.

    Los procesos que muestro a continuación funcionan perfectamente en SqlServer pero no así en SqlCompact 4.0, dándome el error siguiente:

    Las consultas son las mismas y los métodos los mismos, los cuales pongo a continuación.

      Public Function UpdateForSqlServer() As String
    
            Return String.Format("UPDATE BC SET {0} FROM Balances AS BC {1} WHERE BC.PlanConta = '{2}' AND BC.IdEmpresa = '{3}' {4}",
                                m_fields, m_joins, m_plan, m_empresa, m_where)
    
        End Function
    
        Public Function UpdateForSqlCompact() As String
    
            Return String.Format("UPDATE BC SET {0} FROM Balances AS BC {1} WHERE BC.PlanConta = '{2}' AND BC.IdEmpresa = '{3}' {4}",
                                m_fields, m_joins, m_plan, m_empresa, m_where)
    
        End Function
    
    '/////////////////////////////////////////////
    
     Private Sub SetJoinsAndWhereForSQLServer()
    
            Dim sbJ As New StringBuilder()
            Dim sbW As New StringBuilder()
    
            Dim k As Integer = 0
            For Each item In m_clb.CheckedItems
                sbJ.AppendFormat(" INNER JOIN BALANCES AS B{0} ON BC.[Cód_GC] = B{0}.[Cód_GC] AND BC.PlanConta = B{0}.PlanConta", k)
                sbW.AppendFormat(" AND B{0}.idEmpresa='{1}'", k, m_clb.CheckedItems(k))
                k += 1
            Next
    
            m_joins = sbJ.ToString()
            m_where = sbW.ToString()
    
        End Sub
    
        Private Sub SetJoinsAndWhereForSQLCompact()
    
            Dim sbJ As New StringBuilder()
            Dim sbW As New StringBuilder()
    
            Dim k As Integer = 0
            For Each item In m_clb.CheckedItems
                sbJ.AppendFormat(" INNER JOIN BALANCES AS B{0} ON BC.[Cód_GC] = B{0}.[Cód_GC] AND BC.PlanConta = B{0}.PlanConta", k)
                sbW.AppendFormat(" AND B{0}.idEmpresa='{1}'", k, m_clb.CheckedItems(k))
                k += 1
            Next
    
            m_joins = sbJ.ToString()
            m_where = sbW.ToString()
    
    
            '// INNER JOIN BALANCES AS B0 ON BC.[Cód_GC] = B0.[Cód_GC] AND BC.PlanConta = B0.PlanConta INNER JOIN BALANCES AS B1 ON BC.[Cód_GC] = B1.[Cód_GC] AND BC.PlanConta = B1.PlanConta
            '// AND B0.idEmpresa='A01' AND B1.idEmpresa='A02'
        End Sub
    
    '/////////////////////////////////////////
    
     Public Sub Consolidar_Empresas()
    
            Try
                If (cboTablas.SelectedIndex = -1) Then
                    MsgBox("Seleccione la tabla donde desea conciliarlas", vbExclamation)
                    Return
                End If
    
                If ((cboPlanes.SelectedIndex = -1) And (VarGlobal.StrCodPais = VarGlobal.StrCodPais)) Then
                    MsgBox("Seleccione el plan contable", vbExclamation)
                    Return
                End If
    
                If (CheckedListBox1.CheckedItems.Count < 2) Then
                    MsgBox("Marque las tablas que desea conciliar (al menos, dos)", vbExclamation)
                    Return
                End If
    
                '****************************************************************************************
    
                Dim i As Integer
                Dim empresasO As String, empresaD As String, PLAN As String
                empresaD = cboTablas.Text
                empresasO = ""
    
                If (VarGlobal.StrCodPais = "34") Then
                    PLAN = cboPlanes.Text
                ElseIf (VarGlobal.StrCodPais = "57") Then 'Colombia
                    PLAN = "COLOMBIA"
                ElseIf (VarGlobal.StrCodPais = "51") Then 'Peru
                    PLAN = "PERU"
                Else
                    PLAN = "PAISES"
                End If
    
                'Obtener las empresas desde las que se sumarán los balances.
                For i = 0 To cboTablas.Items.Count - 1
                    If CBool(CheckedListBox1.GetItemChecked(CInt(i))) Then
                        'codigos de empresas seleccionadas.
                        empresasO = empresasO & "'" & cboTablas.Items(CInt(i)).ToString & "',"
                    End If
                Next
    
                empresasO = Strings.Left(empresasO, Len(empresasO) - 1)
    
                If (InStr(1, empresasO, empresaD) > 0) Then
                    MsgBox("No puede ser la misma empresa en la que se consolida que las que se toman como orígen de consolidación.", vbExclamation)
                    Return
                End If
    
                'EJECUTAR LA CONSOLIDACION.
                'Creamos el acceso a datos mediante el nombre de la cadena de conexión existente en el archivo de configuración de la aplicación.
                Dim da As Capa_Datos.DataAccessInvariant = DataAccessInvariant.GetDataAccessInvariant(Configuracion.CadenaConexion)
    
                ' Verificar si se está utilizando Access
                Dim forAccess As Boolean = (da.ProviderInvariantName = "System.Data.OleDb")
                ' Verificar si se está utilizando SqlCompact
                Dim forSqlCompact As Boolean = (da.ProviderInvariantName = "System.Data.SqlServerCe.4.0")
                ' Verificar si se está utilizando SqlServer Express
                Dim forSqlServer As Boolean = (da.ProviderInvariantName = "System.Data.SqlClient")
    
                ' Obtenemos la consulta UPDATE
                Dim query As New UpdateConsolidarEmpresas(CheckedListBox1, PLAN, empresaD)
    
                ' Declaramos una variable Connection
                Using cnn As DbConnection = da.CreateConnection()
    
                    ' Creamos el Commando
                    Dim cmd As DbCommand = cnn.CreateCommand
    
                    If (forAccess) = True Then
                        ' Estamos utilizando Access.
                        cmd.CommandText = query.UpdateForAccess()
    
                    ElseIf (forSqlCompact) = True Then
                        ' Estamos utilizando SQL Compact.
                        cmd.CommandText = query.UpdateForSqlCompact()
    
                    ElseIf (forSqlServer) = True Then
    
                        ' Estamos utilizando SQL Server.
                        cmd.CommandText = query.UpdateForSqlServer()
                    End If
    
                    cnn.Open()
    
                    cmd.ExecuteNonQuery()
                    MsgBox("Consolidación finalizada", vbInformation)
                End Using
    
                'SQLSERVER
                'Update BC Set BC.Ejer_01=B0.Ejer_01+B1.Ejer_01, BC.Ejer_02 = B0.Ejer_02 + B1.Ejer_02, BC.Ejer_03 = B0.Ejer_03 + B1.Ejer_03, BC.Ejer_04 = B0.Ejer_04 + B1.Ejer_04,
                'BC.Ejer_05=B0.Ejer_05+B1.Ejer_05,BC.Ejer_06=B0.Ejer_06+B1.Ejer_06,BC.Ejer_07=B0.Ejer_07+B1.Ejer_07,BC.Ejer_08=B0.Ejer_08+B1.Ejer_08,
                'BC.Ejer_09 = B0.Ejer_09 + B1.Ejer_09,BC.Ejer_10=B0.Ejer_10+B1.Ejer_10,BC.Ejer_11=B0.Ejer_11+B1.Ejer_11,BC.Ejer_12=B0.Ejer_12+B1.Ejer_12 
                'From Balances As BC  INNER Join BALANCES As B0 On BC.[Cód_GC] = B0.[Cód_GC] And BC.PlanConta = B0.PlanConta 
                'INNER Join BALANCES As B1 On BC.[Cód_GC] = B1.[Cód_GC] And BC.PlanConta = B1.PlanConta 
                'WHERE BC.PlanConta = 'PLAN 2007' AND BC.IdEmpresa = 'A03'  AND B0.idEmpresa='A01' AND B1.idEmpresa='A02'
    
                'SQL COMPACT
                'UPDATE BC SET BC.Ejer_01=B0.Ejer_01+B1.Ejer_01, BC.Ejer_02 = B0.Ejer_02 + B1.Ejer_02, BC.Ejer_03 = B0.Ejer_03 + B1.Ejer_03, BC.Ejer_04 = B0.Ejer_04 + B1.Ejer_04,
                'BC.Ejer_05=B0.Ejer_05+B1.Ejer_05,BC.Ejer_06=B0.Ejer_06+B1.Ejer_06,BC.Ejer_07=B0.Ejer_07+B1.Ejer_07,BC.Ejer_08=B0.Ejer_08+B1.Ejer_08,
                'BC.Ejer_09 = B0.Ejer_09 + B1.Ejer_09,BC.Ejer_10=B0.Ejer_10+B1.Ejer_10,BC.Ejer_11=B0.Ejer_11+B1.Ejer_11,BC.Ejer_12=B0.Ejer_12+B1.Ejer_12 
                'FROM Balances AS BC  INNER JOIN BALANCES AS B0 ON BC.[Cód_GC] = B0.[Cód_GC] AND BC.PlanConta = B0.PlanConta 
                'INNER Join BALANCES AS B1 ON BC.[Cód_GC] = B1.[Cód_GC] And BC.PlanConta = B1.PlanConta 
                'WHERE BC.PlanConta = 'PLAN 2007' AND BC.IdEmpresa = 'A03'  AND B0.idEmpresa='A01' AND B1.idEmpresa='A02'
            Catch
    
                MsgBox("Error " & Err.Number & " (" & Err.Description & ") en proceso btnConciliar_Click de Formulario frmConciliacion")
    
            End Try
    
        End Sub
    

    He puesto el resultado que arroja el editor de cada una de las 2 sql (SqlServer y COmpact), el resultado es el mismo pero salta el error en el cmd.executenonquery cuando estoy trabajando con Compact.

    No se si el problema puede venir desde el JOIN que puede ser (no lo se) que SqlCOmact lo tenga que tratar de otra manera, pero lo más curioso es que al final las dos sentencias que llegan al executenonquery son las mimas.

    Bueno, gracias a todos y a ver si alguien me pueden dar un poco de luz en el tema.

    Gemma

    jueves, 16 de febrero de 2017 10:25

Respuestas

  • "gemma_campillo" escribió:

    > He puesto el resultado que arroja el editor de cada una de las 2 sql
    > (SqlServer y COmpact), el resultado es el mismo pero salta el error
    > en el cmd.executenonquery cuando estoy trabajando con Compact.
    >
    > No se si el problema puede venir desde el JOIN que puede ser (no lo se)
    > que SqlCOmact lo tenga que tratar de otra manera, ...
    >

    Es raro, porque la consulta T-SQL de actualización sería la misma que para SQL Server.

    Referencia de SQL (SQL Server Compact)

    Cláusula FROM (SQL Server Compact)

    Una pregunta. ¿Por qué sabes que en el procedimiento Consolidar_Empresas hay que utilizar SQL Server Compact? Si después de abrir la conexión consultas el valor de la propiedad ConnectionString, ¿qué cadena de conexión obtienes?

        ' ...

        ' Abrir la conexión
        cnn.Open()

        ' Consultamos el valor de la propiedad ConnectionString
        MessageBox.Show(cnn.ConnectionString)

        cmd.ExecuteNonQuery()

        ' ...

    Te hago esta pregunta porque yo no me fiaría mucho de las siguientes verificaciones que realizas:

    > ' Verificar si se está utilizando Access
    > Dim forAccess As Boolean = (da.ProviderInvariantName = "System.Data.OleDb")
    > ' Verificar si se está utilizando SqlCompact
    > Dim forSqlCompact As Boolean = (da.ProviderInvariantName = "System.Data.SqlServerCe.4.0")
    > ' Verificar si se está utilizando SqlServer Express
    > Dim forSqlServer As Boolean = (da.ProviderInvariantName = "System.Data.SqlClient")

    Y si a esto le unimos que posteriormente no existe el bloque Else en la instrucción If ... End If:

    > If (forAccess) = True Then
    >     ' Estamos utilizando Access.
    >     cmd.CommandText = query.UpdateForAccess()
    >
    > ElseIf (forSqlCompact) = True Then
    >     ' Estamos utilizando SQL Compact.
    >     cmd.CommandText = query.UpdateForSqlCompact()
    >
    > ElseIf (forSqlServer) = True Then
    >    ' Estamos utilizando SQL Server.
    >    cmd.CommandText = query.UpdateForSqlServer()
    >
    > End If

    puede pasar de todo si las variables 'forAccess', 'forSqlCompact' y 'forSqlServer' tienen el valor False.


    > Dim forSqlCompact As Boolean = (da.ProviderInvariantName = "System.Data.SqlServerCe.4.0")

    Si utilizas el operador de comparación igual (=), deberías de saber que por defecto ese operador DISTINGUE entre mayúsculas y minúsculas, salvo que al comienzo del módulo o clase donde se encuentre establezcas el valor Option Compare Text:

    Operadores de comparación (Visual Basic)

    Ignoro en estos momentos de donde tomas el valor de la propiedad ProviderInvariantName, pero vamos a suponer que la tomas de la cadena de conexión con nombre existente en el archivo de configuración de la aplicación, en el famoso app.config. Si es así, ¿estás segura que en dicho archivo figura el nombre del proveedor invariable TAL CUAL lo estás verificando en el código, con las mismas posiciones de letras en mayúscula y minúscula? ¿Y si alguien lo modifica sin querer? ¿Qué sucedería entonces?

    En lugar de utilizar la opción Option Comparte Text, que puede afectar a otras partes del módulo o clase donde lo incluyas, mejor será que utilices otro método de comparación que NO DISTINGA ENTRE MAYÚSCULAS Y MINÚSCULAS, como bien puede ser la sobrecarga del Método String.Equals (String, String, StringComparison) de la clase System.String:

        ' Verificar si se está utilizando Access
        Dim forAccess As Boolean = da.ProviderInvariantName.Equals("System.Data.OleDb", StringComparison .CurrentCultureIgnoreCase)
    
        ' Verificar si se está utilizando SqlCompact
        Dim forSqlCompact As Boolean = da.ProviderInvariantName.Equals("System.Data.SqlServerCe.4.0", StringComparison .CurrentCultureIgnoreCase)
    
        ' Verificar si se está utilizando SqlServer Express
        Dim forSqlServer As Boolean = da.ProviderInvariantName.Equals("System.Data.SqlClient", StringComparison .CurrentCultureIgnoreCase)

    Y ahora, el bloque If ... End If se quedaría así:

        If (forAccess) Then
            ' Estamos utilizando Access.
            cmd.CommandText = query.UpdateForAccess()
    
        ElseIf (forSqlCompact) Then
            ' Estamos utilizando SQL Compact.
            cmd.CommandText = query.UpdateForSqlCompact()
    
        ElseIf (forSqlServer) Then
            ' Estamos utilizando SQL Server.
            cmd.CommandText = query.UpdateForSqlServer()
    
        Else
            MessageBox.Show("El proveedor invariable utilizado no está soportado actualmente.")
    
            ' Abandonar el procedimiento
            Return
    
        End If

    De ésta manera protegemos un poquito más nuestra aplicación ante cualquier imprevisto que se presente.

    Siento no poder decirte el motivo por el cual obtienes el error cuando ejecutas la consulta UPDATE utilizando SQL Server Compact, pero es que lo desconozco, ya que entiendo que la sintaxis de la consulta T-SQL es correcta.

     


    Enrique Martínez Montejo
    [MS MVP - Visual Studio y Tecnologías de Desarrollo]

    Nota informativa: La información contenida en este mensaje, así como el código fuente incluido en el mismo, se proporciona «COMO ESTÁ», sin garantías de ninguna clase, y no otorga derecho alguno. Usted asume cualquier riesgo al poner en práctica, utilizar o ejecutar lo recomendado o sugerido en el presente mensaje.

    Si esta respuesta le ha resultado útil, recuerde marcarla como satisfactoria.

    Si usas Visual Basic .NET y deseas ser productivo y feliz, se inteligente y activa la instrucción
    Option Strict.



    jueves, 16 de febrero de 2017 12:49
    Moderador
  • "gemma_campillo" escribió:

    > Cuando todo parece que está funcionando perfectamente, zas, leñazo al canto.
    >
    > Menuda leche.
    >
    > Buen, voy a buscar la información y sigo con lo que me has indicado.

    No te desanimes que tampoco es para tanto. Tan solo tienes que rellenar un objeto DataTable con los datos de las dos tablas BALANCES que deseas consolidar, previa suma de los campos de las dos tablas.

    Si no me he equivocado, ésta sería la consulta de selección de datos combinados con la que rellenarías el primer objeto DataTable:

    SELECT (B0.Ejer_01+B1.Ejer_01) AS Campo1, (B0.Ejer_02+B1.Ejer_02) AS Campo2, (B0.Ejer_03+B1.Ejer_03) AS Campo3,
    (B0.Ejer_04+B1.Ejer_04) AS Campo4, (B0.Ejer_05+B1.Ejer_05) AS Campo5, (B0.Ejer_06+B1.Ejer_06) As Campo6,
    (B0.Ejer_07+B1.Ejer_07) AS Campo7, (B0.Ejer_08+B1.Ejer_08) AS Campo8, (B0.Ejer_09+B1.Ejer_09) AS Campo9,
    (B0.Ejer_10+B1.Ejer_10) AS Campo10, (B0.Ejer_11+B1.Ejer_11) AS Campo11, (B0.Ejer_12+B1.Ejer_12) AS Campo12 
    FROM Balances AS B1 INNER JOIN BALANCES AS B0 ON B1.[Cód_GC] = B0.[Cód_GC] AND B1.PlanConta = B0.PlanConta 
    WHERE B0.PlanConta='PLAN 2007' AND B0.IdEmpresa='A01' AND B1.IdEmpresa='A02'
    ORDER BY B0.IdEmpresa

    Revisa bien que no me haya equivocado al escribir los campos, y sobre todo, la cláusula WHERE.

    Observa que en el objeto DataTable relleno ya tenemos sumados los valores individuales de los campos pertenecientes a las dos tablas.

    Después rellenarías un segundo objeto DataTable con los datos que actualmente tiene la tabla BALANCES, ordenado también por el mismo campo que la consulta de selección anterior:

       
    SELECT * FROM Balances ORDER BY IdEmpresa

    Posteriormente conforme recorres los registros existentes en el primer objeto DataTable, vas actualizando los registros del segundo objeto DataTable.

    Y por último, configurarías un adaptador de datos para ejecutar su método Update pasándole el segundo objeto DataTable. Ni que decir tiene que la tabla que deseas actualizar tiene que disponer de su correspondiente clave principal.

    Como no dispongo de los datos de tu tabla de SQL Compact, me he tenido que inventar un ejemplo, el cual utiliza una supuesta tabla de Facturas para actualizar los campos Base, IVA y Total de otra tabla llamada Facturas3, con la suma de los valores de dichos campos correspondientes a dos tablas de una misma tabla Facturas. ¡Qué lío! Espero que se entienda:

        Private Sub Button1_Click(sender As Object, e As EventArgs) Handles Button1.Click
    
            Try
                ' Configuramos la conexión con la base de datos de SQL Compact
                '
                Using cnn As New SqlCeConnection(cadenaConexionSqlServerCompact)
    
                    ' Obtener un objeto DataTable como resultado de
                    ' sumar los campos de las dos tablas que deseamos
                    ' consolidar, ordenados los registros de manera
                    ' ascendente por el campo que conforma la clave
                    ' principal de la primera tabla.
                    '
                    Dim dt1 As New DataTable()
                    Dim cmd As SqlCeCommand = cnn.CreateCommand()
                    cmd.CommandText = "SELECT f1.IdFactura, (f1.Base + f2.Base) As Base, " &
                        "(f1.IVA + f2.IVA) As IVA, (f1.Total + f2.Total) As Total " &
                        "FROM Facturas AS f2 INNER JOIN Facturas AS f1 ON f2.IdFactura = f1.IdFactura " &
                        "ORDER BY f1.IdFactura ASC"
    
                    Dim da As New SqlCeDataAdapter(cmd)
                    da.Fill(dt1)
    
                    ' Obtener un objeto DataTable con los datos de la tabla
                    ' donde deseamos reflejar los datos consolidados, ordenados
                    ' los registros de manera ascendente por el campo que conforma
                    ' la clave principal de la tabla.
                    '
                    Dim dt2 As New DataTable()
                    cmd = cnn.CreateCommand()
                    cmd.CommandText = "SELECT * FROM Facturas3 ORDER BY IdFactura ASC"
                    da = New SqlCeDataAdapter(cmd)
                    da.Fill(dt2)
    
                    ' Conforme recorremos los registros de la primera tabla
                    ' vamos actualizando los datos de la segunda tabla.
                    '
                    For Each row As DataRow In dt1.Rows
                        Dim rows2 As DataRow() = dt2.Select(String.Format("IdFactura = {0}", row("IdFactura")))
                        If (rows2.Length > 0) Then
                            ' Actualizar el segundo objeto DataTable.
                            rows2(0)("Base") = row("Base")
                            rows2(0)("IVA") = row("IVA")
                            rows2(0)("Total") = row("Total")
                        End If
                    Next
    
                    ' Configuramos el ÚLTIMO adaptador de datos creado para
                    ' proceder a actualizar en la base de datos la tabla
                    ' Factura3 con los datos existentes en el segundo objeto
                    ' DataTable.
                    '
                    Dim cb As New SqlCeCommandBuilder(da)
                    cb.QuotePrefix = "["
                    cb.QuoteSuffix = "]"
                    da.UpdateCommand = cb.GetUpdateCommand()
    
                    Dim n As Integer = da.Update(dt2)
                    MessageBox.Show("Nº de registros actualizados: " & n.ToString())
    
                End Using
    
            Catch ex As Exception
                MessageBox.Show(ex.Message)
    
            End Try
    
        End Sub

    Obviamente, cuantos más registros existan para actualizar la operación tardará más tiempo, aunque tampoco es para "tirarse de los pelos", porque no creo que el cliente esté cada dos minutos consolidando datos, ¿o sí estará todo el rato consolidando datos? ;-)

    En fin, adapta el ejemplo a tus necesidades para ver si con ello sales del paso para consolidar los datos de la base de SQL Server Compact.


    Enrique Martínez Montejo
    [MS MVP - Visual Studio y Tecnologías de Desarrollo]

    Nota informativa: La información contenida en este mensaje, así como el código fuente incluido en el mismo, se proporciona «COMO ESTÁ», sin garantías de ninguna clase, y no otorga derecho alguno. Usted asume cualquier riesgo al poner en práctica, utilizar o ejecutar lo recomendado o sugerido en el presente mensaje.

    Si esta respuesta le ha resultado útil, recuerde marcarla como satisfactoria.

    Si usas Visual Basic .NET y deseas ser productivo y feliz, se inteligente y activa la instrucción
    Option Strict.






    jueves, 16 de febrero de 2017 18:47
    Moderador
  • He modificado el ejemplo que te indiqué más arriba para ver si así puedes actualizar los datos de la tabla Balances como resultado de la consolidación de dos empresas, porque digo yo que como mucho serán dos empresas, o por el contrario pueden ser 3, 10, 20 empresas cuyos datos se consoliden a la misma vez.

        Private Sub Button1_Click(sender As Object, e As EventArgs) Handles Button1.Click
    
            Try
                ' Configuramos la conexión con la base de datos de SQL Compact
                '
                Using cnn As New SqlCeConnection(cadenaConexionSqlServerCe)
    
                    ' Obtener un objeto DataTable como resultado de sumar
                    ' los campos de los ejercicios correspondientes a las
                    ' dos empresas que deseamos consolidar, ordenados de
                    ' manera ascendente por el campo Cód_GC de la tabla.
                    '
                    Dim dt1 As New DataTable()
                    Dim cmd As SqlCeCommand = cnn.CreateCommand()
                    cmd.CommandText = "SELECT BC.[Cód_GC], (BC.Ejer_01+B0.Ejer_01) AS Ej01, ([BC].[Ejer_02]+[B0].[Ejer_02]) AS Ej02," &
                        "([BC].[Ejer_03]+[B0].[Ejer_03]) AS Ej03, ([BC].[Ejer_04]+[B0].[Ejer_04]) AS Ej04," &
                        "([BC].[Ejer_05]+[B0].[Ejer_05]) AS Ej05, ([BC].[Ejer_06]+[B0].[Ejer_06]) AS Ej06," &
                        "(BC.Ejer_07+B0.Ejer_07) AS Ej07, ([BC].[Ejer_08]+[B0].[Ejer_08]) AS Ej08," &
                        "([BC].[Ejer_09]+[B0].[Ejer_09]) AS Ej09, ([BC].[Ejer_10]+[B0].[Ejer_10]) AS Ej10," &
                        "([BC].[Ejer_11]+[B0].[Ejer_11]) AS Ej11, ([BC].[Ejer_12]+[B0].[Ejer_12]) AS Ej12 " &
                        "FROM Balances AS BC INNER JOIN Balances AS B0 ON BC.[Cód_GC] = B0.[Cód_GC] " &
                        "WHERE BC.PlanConta = 'PLAN 2007' AND BC.IdEmpresa='A01' AND B0.IdEmpresa='A02' " &
                        "ORDER BY B0.[Cód_GC]"
    
                    Dim da As New SqlCeDataAdapter(cmd)
                    da.Fill(dt1)
    
                    ' Obtener un objeto DataTable con los datos de la empresa
                    ' donde deseamos reflejar los datos consolidados, ordenados
                    ' los registros por el campo que Cód_GC.
                    '
                    Dim dt2 As New DataTable()
                    cmd = cnn.CreateCommand()
                    cmd.CommandText =
                        "SELECT * FROM Balances " &
                        "WHERE PlanConta = 'PLAN 2007' AND IdEmpresa='A03' " &
                        "ORDER BY [Cód_GC]"
    
                    da = New SqlCeDataAdapter(cmd)
                    da.Fill(dt2)
    
                    ' Conforme recorremos los registros del primer objeto
                    ' DataTable vamos actualizando los datos del segundo
                    ' objeto DataTable.
                    '
                    For Each row As DataRow In dt1.Rows
                        Dim rows2 As DataRow() = dt2.Select(String.Format("Cód_GC = '{0}'", row("Cód_GC")))
                        If (rows2.Length > 0) Then
                            ' Actualizar la tabla temporal 
                            rows2(0)("Ejer_01") = row("Ej01")
                            rows2(0)("Ejer_02") = row("Ej02")
                            rows2(0)("Ejer_03") = row("Ej03")
                            rows2(0)("Ejer_04") = row("Ej04")
                            rows2(0)("Ejer_05") = row("Ej05")
                            rows2(0)("Ejer_06") = row("Ej06")
                            rows2(0)("Ejer_07") = row("Ej07")
                            rows2(0)("Ejer_08") = row("Ej08")
                            rows2(0)("Ejer_09") = row("Ej09")
                            rows2(0)("Ejer_10") = row("Ej10")
                            rows2(0)("Ejer_11") = row("Ej11")
                            rows2(0)("Ejer_12") = row("Ej12")
                        End If
                    Next
    
                    ' Configuramos el ÚLTIMO adaptador de datos creado para
                    ' proceder a actualizar en la base de datos la tabla
                    ' Balances con los datos existentes en el segundo objeto
                    ' DataTable.
                    '
                    Dim cb As New SqlCeCommandBuilder(da)
                    cb.QuotePrefix = "["
                    cb.QuoteSuffix = "]"
                    da.UpdateCommand = cb.GetUpdateCommand()
    
                    Dim n As Integer = da.Update(dt2)
                    MessageBox.Show("Nº de registros actualizados: " & n.ToString())
    
                End Using
    
            Catch ex As Exception
                MessageBox.Show(ex.Message)
    
            End Try
    
        End Sub
    

    La he probado y parece ser que funciona. Como podrás observar, el procedimiento es el mismo: primero seleccionamos un objeto DataTable donde los valores de los campos ya están sumados, y después vamos actualizando, uno a uno, los registros de la empresa donde deseas que aparezcan los datos consolidados.

    Es como si ejecutáramos una consulta UPDATE por cada registro que deseamos actualizar, pero que en lugar de hacerlo nosotros, se encargará de ello el método Update del adaptador de datos que hemos configurado.


    Enrique Martínez Montejo
    [MS MVP - Visual Studio y Tecnologías de Desarrollo]

    Nota informativa: La información contenida en este mensaje, así como el código fuente incluido en el mismo, se proporciona «COMO ESTÁ», sin garantías de ninguna clase, y no otorga derecho alguno. Usted asume cualquier riesgo al poner en práctica, utilizar o ejecutar lo recomendado o sugerido en el presente mensaje.

    Si esta respuesta le ha resultado útil, recuerde marcarla como satisfactoria.

    Si usas Visual Basic .NET y deseas ser productivo y feliz, se inteligente y activa la instrucción
    Option Strict.

    • Marcado como respuesta gemma_campillo sábado, 18 de febrero de 2017 8:59
    sábado, 18 de febrero de 2017 8:17
    Moderador
  • "gemma_campillo" escribió:

    > Siempre me pasan cosas raras, es una leche esto.
    >
    > Voy a seguir mirando a ver si por casualidad suena la flauta.

    Espera un momento que me parece a mí que va a ser difícil que te suene la flauta queriendo ejecutar la consulta UPDATE que has indicado mediante SQL Server Compact. Analicemos la consulta de actualización:

    > 'SQL COMPACT
    > UPDATE BC SET BC.Ejer_01=B0.Ejer_01+B1.Ejer_01, ...
    > FROM Balances AS BC INNER JOIN BALANCES AS B0 ON BC.[Cód_GC] = B0.[Cód_GC] AND BC.PlanConta = B0.PlanConta
    > INNER Join BALANCES AS B1 ON BC.[Cód_GC] = B1.[Cód_GC] And BC.PlanConta = B1.PlanConta
    > WHERE BC.PlanConta = 'PLAN 2007' AND BC.IdEmpresa = 'A03'  AND B0.idEmpresa='A01' AND B1.idEmpresa='A02'

    Esa consulta está bien para actualizar una tabla con los datos existentes en otra tabla, pero SIEMPRE Y CUANDO utilices Microsoft SQL Server, no SQL Server Compact, ya que éste motor no soporta la cláusula FROM en la consulta UPDATE:

    UPDATE (SQL Server Compact)

    Observa que la sintaxis de la consulta UPDATE es la siguiente:

        UPDATE table_name 
           [ WITH ( < table_hint > ) ]
           SET 
           { column_name = { expression | DEFAULT | NULL } } [ ,...n ] 
           [ WHERE < search_condition > ] 
           [ OPTION ( <query_hint> [ ,...n ] ) ]

    y aquí no aparece la cláusula FROM por ningún lado. En cambio, si no vamos a la sintaxis de la consulta UPDATE de Microsoft SQL Server, ésta sí admite la cláusula FROM, como en el ejemplo que aparece en el apartado A. Usar la instrucción UPDATE con información de otra tabla:

        USE AdventureWorks2012;  
        GO  
        UPDATE Sales.SalesPerson  
        SET SalesYTD = SalesYTD + SubTotal  
        FROM Sales.SalesPerson AS sp  
        JOIN Sales.SalesOrderHeader AS so  
        ON sp.BusinessEntityID = so.SalesPersonID  
        AND so.OrderDate = (SELECT MAX(OrderDate)  
                            FROM Sales.SalesOrderHeader  
                            WHERE SalesPersonID = sp.BusinessEntityID);  
        GO  

    Tienes que tener en cuenta que hay diferencias de sintaxis entre el lenguaje de consulta de SQL Server y el de SQL Server Compact, por lo que tendrás que consultar la Referencia de SQL Server Compact para conocer si puedes ejecutar la misma sintaxis de SQL Server.

    Por ejemplo, SQL Server Compact tampoco admite copiar tablas mediante la consulta de creación de tabla SELECT * INTO, cosa que sí admite SQL Server, Access y otros motores de datos:

    SELECT * INTO TablaNueva FROM TablaExistente

    En SQL Server Compact habría que crear primero la tabla (CREATE TABLE) y posteriormente insertar los registros mediante una consulta INSERT INTO.

    Así que, salvo que yo esté equivocado, en SQL Server Compact vas a tener que consolidar los datos de otra manera diferente a como lo haces con SQL Server. ;-)


    Enrique Martínez Montejo
    [MS MVP - Visual Studio y Tecnologías de Desarrollo]

    Nota informativa: La información contenida en este mensaje, así como el código fuente incluido en el mismo, se proporciona «COMO ESTÁ», sin garantías de ninguna clase, y no otorga derecho alguno. Usted asume cualquier riesgo al poner en práctica, utilizar o ejecutar lo recomendado o sugerido en el presente mensaje.

    Si esta respuesta le ha resultado útil, recuerde marcarla como satisfactoria.

    Si usas Visual Basic .NET y deseas ser productivo y feliz, se inteligente y activa la instrucción
    Option Strict.


    jueves, 16 de febrero de 2017 16:48
    Moderador

Todas las respuestas

  • "gemma_campillo" escribió:

    > He puesto el resultado que arroja el editor de cada una de las 2 sql
    > (SqlServer y COmpact), el resultado es el mismo pero salta el error
    > en el cmd.executenonquery cuando estoy trabajando con Compact.
    >
    > No se si el problema puede venir desde el JOIN que puede ser (no lo se)
    > que SqlCOmact lo tenga que tratar de otra manera, ...
    >

    Es raro, porque la consulta T-SQL de actualización sería la misma que para SQL Server.

    Referencia de SQL (SQL Server Compact)

    Cláusula FROM (SQL Server Compact)

    Una pregunta. ¿Por qué sabes que en el procedimiento Consolidar_Empresas hay que utilizar SQL Server Compact? Si después de abrir la conexión consultas el valor de la propiedad ConnectionString, ¿qué cadena de conexión obtienes?

        ' ...

        ' Abrir la conexión
        cnn.Open()

        ' Consultamos el valor de la propiedad ConnectionString
        MessageBox.Show(cnn.ConnectionString)

        cmd.ExecuteNonQuery()

        ' ...

    Te hago esta pregunta porque yo no me fiaría mucho de las siguientes verificaciones que realizas:

    > ' Verificar si se está utilizando Access
    > Dim forAccess As Boolean = (da.ProviderInvariantName = "System.Data.OleDb")
    > ' Verificar si se está utilizando SqlCompact
    > Dim forSqlCompact As Boolean = (da.ProviderInvariantName = "System.Data.SqlServerCe.4.0")
    > ' Verificar si se está utilizando SqlServer Express
    > Dim forSqlServer As Boolean = (da.ProviderInvariantName = "System.Data.SqlClient")

    Y si a esto le unimos que posteriormente no existe el bloque Else en la instrucción If ... End If:

    > If (forAccess) = True Then
    >     ' Estamos utilizando Access.
    >     cmd.CommandText = query.UpdateForAccess()
    >
    > ElseIf (forSqlCompact) = True Then
    >     ' Estamos utilizando SQL Compact.
    >     cmd.CommandText = query.UpdateForSqlCompact()
    >
    > ElseIf (forSqlServer) = True Then
    >    ' Estamos utilizando SQL Server.
    >    cmd.CommandText = query.UpdateForSqlServer()
    >
    > End If

    puede pasar de todo si las variables 'forAccess', 'forSqlCompact' y 'forSqlServer' tienen el valor False.


    > Dim forSqlCompact As Boolean = (da.ProviderInvariantName = "System.Data.SqlServerCe.4.0")

    Si utilizas el operador de comparación igual (=), deberías de saber que por defecto ese operador DISTINGUE entre mayúsculas y minúsculas, salvo que al comienzo del módulo o clase donde se encuentre establezcas el valor Option Compare Text:

    Operadores de comparación (Visual Basic)

    Ignoro en estos momentos de donde tomas el valor de la propiedad ProviderInvariantName, pero vamos a suponer que la tomas de la cadena de conexión con nombre existente en el archivo de configuración de la aplicación, en el famoso app.config. Si es así, ¿estás segura que en dicho archivo figura el nombre del proveedor invariable TAL CUAL lo estás verificando en el código, con las mismas posiciones de letras en mayúscula y minúscula? ¿Y si alguien lo modifica sin querer? ¿Qué sucedería entonces?

    En lugar de utilizar la opción Option Comparte Text, que puede afectar a otras partes del módulo o clase donde lo incluyas, mejor será que utilices otro método de comparación que NO DISTINGA ENTRE MAYÚSCULAS Y MINÚSCULAS, como bien puede ser la sobrecarga del Método String.Equals (String, String, StringComparison) de la clase System.String:

        ' Verificar si se está utilizando Access
        Dim forAccess As Boolean = da.ProviderInvariantName.Equals("System.Data.OleDb", StringComparison .CurrentCultureIgnoreCase)
    
        ' Verificar si se está utilizando SqlCompact
        Dim forSqlCompact As Boolean = da.ProviderInvariantName.Equals("System.Data.SqlServerCe.4.0", StringComparison .CurrentCultureIgnoreCase)
    
        ' Verificar si se está utilizando SqlServer Express
        Dim forSqlServer As Boolean = da.ProviderInvariantName.Equals("System.Data.SqlClient", StringComparison .CurrentCultureIgnoreCase)

    Y ahora, el bloque If ... End If se quedaría así:

        If (forAccess) Then
            ' Estamos utilizando Access.
            cmd.CommandText = query.UpdateForAccess()
    
        ElseIf (forSqlCompact) Then
            ' Estamos utilizando SQL Compact.
            cmd.CommandText = query.UpdateForSqlCompact()
    
        ElseIf (forSqlServer) Then
            ' Estamos utilizando SQL Server.
            cmd.CommandText = query.UpdateForSqlServer()
    
        Else
            MessageBox.Show("El proveedor invariable utilizado no está soportado actualmente.")
    
            ' Abandonar el procedimiento
            Return
    
        End If

    De ésta manera protegemos un poquito más nuestra aplicación ante cualquier imprevisto que se presente.

    Siento no poder decirte el motivo por el cual obtienes el error cuando ejecutas la consulta UPDATE utilizando SQL Server Compact, pero es que lo desconozco, ya que entiendo que la sintaxis de la consulta T-SQL es correcta.

     


    Enrique Martínez Montejo
    [MS MVP - Visual Studio y Tecnologías de Desarrollo]

    Nota informativa: La información contenida en este mensaje, así como el código fuente incluido en el mismo, se proporciona «COMO ESTÁ», sin garantías de ninguna clase, y no otorga derecho alguno. Usted asume cualquier riesgo al poner en práctica, utilizar o ejecutar lo recomendado o sugerido en el presente mensaje.

    Si esta respuesta le ha resultado útil, recuerde marcarla como satisfactoria.

    Si usas Visual Basic .NET y deseas ser productivo y feliz, se inteligente y activa la instrucción
    Option Strict.



    jueves, 16 de febrero de 2017 12:49
    Moderador
  • Hola maestro, como estás?

    Espero que estés muy bien. Bueno, la conexión que lleva como me indicas en tu pregunta es correcta: Data Source=|DataDirectory|\PerseoSQLce.sdf;Password=xxxxxxx

    Y la cnn = SystemData.SqlServerCe.SqlConnection

    Le he puesto el return y la comparación tal como me has indicado, pero continúa con el mismo error.

    Lo he repasado y reseguido varias veces y no se para en ningún sitio, pasa correctamente y los datos que lleva porque he hecho la prueba y he apuntado lo que salía en SqlServer y lo que salía en Compact y es lo mismo.

    Siempre me pasan cosas raras, es una leche esto.

    Bueno, simplemente que es un gran honor y placer volverte a saludar como siempre querido amigo.

    Voy a seguir mirando a ver si por casualidad suena la flauta.

    Un abrazo muy fuerte Enrique.

    Gemma


    jueves, 16 de febrero de 2017 15:00
  • Hola:

    La consulta si la pruebo en el IDE de SqlServer se ejecuta perfectamente, no da problemas.

    Ahora bien, la misma en el IDE de Compact da el mismo error que hay en la imagen.

    UPDATE BC SET BC.Ejer_01=B0.Ejer_01+B1.Ejer_01, BC.Ejer_02 = B0.Ejer_02 + B1.Ejer_02, BC.Ejer_03 = B0.Ejer_03 + B1.Ejer_03, BC.Ejer_04 = B0.Ejer_04 + B1.Ejer_04,
                BC.Ejer_05=B0.Ejer_05+B1.Ejer_05,BC.Ejer_06=B0.Ejer_06+B1.Ejer_06,BC.Ejer_07=B0.Ejer_07+B1.Ejer_07,BC.Ejer_08=B0.Ejer_08+B1.Ejer_08,
                BC.Ejer_09 = B0.Ejer_09 + B1.Ejer_09,BC.Ejer_10=B0.Ejer_10+B1.Ejer_10,BC.Ejer_11=B0.Ejer_11+B1.Ejer_11,BC.Ejer_12=B0.Ejer_12+B1.Ejer_12 
                FROM Balances AS BC  INNER JOIN BALANCES AS B0 ON BC.[Cód_GC] = B0.[Cód_GC] AND BC.PlanConta = B0.PlanConta 
                INNER Join BALANCES AS B1 ON BC.[Cód_GC] = B1.[Cód_GC] And BC.PlanConta = B1.PlanConta 
                WHERE BC.PlanConta = 'PLAN 2007' AND BC.IdEmpresa = 'A03'  AND B0.idEmpresa='A01' AND B1.idEmpresa='A02'

    Algo tiene que haber de diferente en el tratamiento de la consulta en SqlCompact para que de error. Es que en Access tampoco da error, la ejecuta perfectamente. Y marca el error a partir de la cláusula FROM.

    Bueno, por si sirve de alguna cosa.

    Sigo investigando.

    Un saludo.

    Gemma


    jueves, 16 de febrero de 2017 16:47
  • "gemma_campillo" escribió:

    > Siempre me pasan cosas raras, es una leche esto.
    >
    > Voy a seguir mirando a ver si por casualidad suena la flauta.

    Espera un momento que me parece a mí que va a ser difícil que te suene la flauta queriendo ejecutar la consulta UPDATE que has indicado mediante SQL Server Compact. Analicemos la consulta de actualización:

    > 'SQL COMPACT
    > UPDATE BC SET BC.Ejer_01=B0.Ejer_01+B1.Ejer_01, ...
    > FROM Balances AS BC INNER JOIN BALANCES AS B0 ON BC.[Cód_GC] = B0.[Cód_GC] AND BC.PlanConta = B0.PlanConta
    > INNER Join BALANCES AS B1 ON BC.[Cód_GC] = B1.[Cód_GC] And BC.PlanConta = B1.PlanConta
    > WHERE BC.PlanConta = 'PLAN 2007' AND BC.IdEmpresa = 'A03'  AND B0.idEmpresa='A01' AND B1.idEmpresa='A02'

    Esa consulta está bien para actualizar una tabla con los datos existentes en otra tabla, pero SIEMPRE Y CUANDO utilices Microsoft SQL Server, no SQL Server Compact, ya que éste motor no soporta la cláusula FROM en la consulta UPDATE:

    UPDATE (SQL Server Compact)

    Observa que la sintaxis de la consulta UPDATE es la siguiente:

        UPDATE table_name 
           [ WITH ( < table_hint > ) ]
           SET 
           { column_name = { expression | DEFAULT | NULL } } [ ,...n ] 
           [ WHERE < search_condition > ] 
           [ OPTION ( <query_hint> [ ,...n ] ) ]

    y aquí no aparece la cláusula FROM por ningún lado. En cambio, si no vamos a la sintaxis de la consulta UPDATE de Microsoft SQL Server, ésta sí admite la cláusula FROM, como en el ejemplo que aparece en el apartado A. Usar la instrucción UPDATE con información de otra tabla:

        USE AdventureWorks2012;  
        GO  
        UPDATE Sales.SalesPerson  
        SET SalesYTD = SalesYTD + SubTotal  
        FROM Sales.SalesPerson AS sp  
        JOIN Sales.SalesOrderHeader AS so  
        ON sp.BusinessEntityID = so.SalesPersonID  
        AND so.OrderDate = (SELECT MAX(OrderDate)  
                            FROM Sales.SalesOrderHeader  
                            WHERE SalesPersonID = sp.BusinessEntityID);  
        GO  

    Tienes que tener en cuenta que hay diferencias de sintaxis entre el lenguaje de consulta de SQL Server y el de SQL Server Compact, por lo que tendrás que consultar la Referencia de SQL Server Compact para conocer si puedes ejecutar la misma sintaxis de SQL Server.

    Por ejemplo, SQL Server Compact tampoco admite copiar tablas mediante la consulta de creación de tabla SELECT * INTO, cosa que sí admite SQL Server, Access y otros motores de datos:

    SELECT * INTO TablaNueva FROM TablaExistente

    En SQL Server Compact habría que crear primero la tabla (CREATE TABLE) y posteriormente insertar los registros mediante una consulta INSERT INTO.

    Así que, salvo que yo esté equivocado, en SQL Server Compact vas a tener que consolidar los datos de otra manera diferente a como lo haces con SQL Server. ;-)


    Enrique Martínez Montejo
    [MS MVP - Visual Studio y Tecnologías de Desarrollo]

    Nota informativa: La información contenida en este mensaje, así como el código fuente incluido en el mismo, se proporciona «COMO ESTÁ», sin garantías de ninguna clase, y no otorga derecho alguno. Usted asume cualquier riesgo al poner en práctica, utilizar o ejecutar lo recomendado o sugerido en el presente mensaje.

    Si esta respuesta le ha resultado útil, recuerde marcarla como satisfactoria.

    Si usas Visual Basic .NET y deseas ser productivo y feliz, se inteligente y activa la instrucción
    Option Strict.


    jueves, 16 de febrero de 2017 16:48
    Moderador
  • Hola maestro:

    Siempre te molesto, bueno, por ahora me queda claro que el problema es el motor para ese tipo de consulta.

    Voy a intentar seguir los pasos que me has indicado a ver que saco.

    Cuando todo parece que está funcionando perfectamente, zas, leñazo al canto.

    Menuda leche.

    Buen, voy a buscar la información y sigo con lo que me has indicado.

    Un abrazo querido amigo.

    Gemma

    jueves, 16 de febrero de 2017 17:10
  • "gemma_campillo" escribió:

    > Cuando todo parece que está funcionando perfectamente, zas, leñazo al canto.
    >
    > Menuda leche.
    >
    > Buen, voy a buscar la información y sigo con lo que me has indicado.

    No te desanimes que tampoco es para tanto. Tan solo tienes que rellenar un objeto DataTable con los datos de las dos tablas BALANCES que deseas consolidar, previa suma de los campos de las dos tablas.

    Si no me he equivocado, ésta sería la consulta de selección de datos combinados con la que rellenarías el primer objeto DataTable:

    SELECT (B0.Ejer_01+B1.Ejer_01) AS Campo1, (B0.Ejer_02+B1.Ejer_02) AS Campo2, (B0.Ejer_03+B1.Ejer_03) AS Campo3,
    (B0.Ejer_04+B1.Ejer_04) AS Campo4, (B0.Ejer_05+B1.Ejer_05) AS Campo5, (B0.Ejer_06+B1.Ejer_06) As Campo6,
    (B0.Ejer_07+B1.Ejer_07) AS Campo7, (B0.Ejer_08+B1.Ejer_08) AS Campo8, (B0.Ejer_09+B1.Ejer_09) AS Campo9,
    (B0.Ejer_10+B1.Ejer_10) AS Campo10, (B0.Ejer_11+B1.Ejer_11) AS Campo11, (B0.Ejer_12+B1.Ejer_12) AS Campo12 
    FROM Balances AS B1 INNER JOIN BALANCES AS B0 ON B1.[Cód_GC] = B0.[Cód_GC] AND B1.PlanConta = B0.PlanConta 
    WHERE B0.PlanConta='PLAN 2007' AND B0.IdEmpresa='A01' AND B1.IdEmpresa='A02'
    ORDER BY B0.IdEmpresa

    Revisa bien que no me haya equivocado al escribir los campos, y sobre todo, la cláusula WHERE.

    Observa que en el objeto DataTable relleno ya tenemos sumados los valores individuales de los campos pertenecientes a las dos tablas.

    Después rellenarías un segundo objeto DataTable con los datos que actualmente tiene la tabla BALANCES, ordenado también por el mismo campo que la consulta de selección anterior:

       
    SELECT * FROM Balances ORDER BY IdEmpresa

    Posteriormente conforme recorres los registros existentes en el primer objeto DataTable, vas actualizando los registros del segundo objeto DataTable.

    Y por último, configurarías un adaptador de datos para ejecutar su método Update pasándole el segundo objeto DataTable. Ni que decir tiene que la tabla que deseas actualizar tiene que disponer de su correspondiente clave principal.

    Como no dispongo de los datos de tu tabla de SQL Compact, me he tenido que inventar un ejemplo, el cual utiliza una supuesta tabla de Facturas para actualizar los campos Base, IVA y Total de otra tabla llamada Facturas3, con la suma de los valores de dichos campos correspondientes a dos tablas de una misma tabla Facturas. ¡Qué lío! Espero que se entienda:

        Private Sub Button1_Click(sender As Object, e As EventArgs) Handles Button1.Click
    
            Try
                ' Configuramos la conexión con la base de datos de SQL Compact
                '
                Using cnn As New SqlCeConnection(cadenaConexionSqlServerCompact)
    
                    ' Obtener un objeto DataTable como resultado de
                    ' sumar los campos de las dos tablas que deseamos
                    ' consolidar, ordenados los registros de manera
                    ' ascendente por el campo que conforma la clave
                    ' principal de la primera tabla.
                    '
                    Dim dt1 As New DataTable()
                    Dim cmd As SqlCeCommand = cnn.CreateCommand()
                    cmd.CommandText = "SELECT f1.IdFactura, (f1.Base + f2.Base) As Base, " &
                        "(f1.IVA + f2.IVA) As IVA, (f1.Total + f2.Total) As Total " &
                        "FROM Facturas AS f2 INNER JOIN Facturas AS f1 ON f2.IdFactura = f1.IdFactura " &
                        "ORDER BY f1.IdFactura ASC"
    
                    Dim da As New SqlCeDataAdapter(cmd)
                    da.Fill(dt1)
    
                    ' Obtener un objeto DataTable con los datos de la tabla
                    ' donde deseamos reflejar los datos consolidados, ordenados
                    ' los registros de manera ascendente por el campo que conforma
                    ' la clave principal de la tabla.
                    '
                    Dim dt2 As New DataTable()
                    cmd = cnn.CreateCommand()
                    cmd.CommandText = "SELECT * FROM Facturas3 ORDER BY IdFactura ASC"
                    da = New SqlCeDataAdapter(cmd)
                    da.Fill(dt2)
    
                    ' Conforme recorremos los registros de la primera tabla
                    ' vamos actualizando los datos de la segunda tabla.
                    '
                    For Each row As DataRow In dt1.Rows
                        Dim rows2 As DataRow() = dt2.Select(String.Format("IdFactura = {0}", row("IdFactura")))
                        If (rows2.Length > 0) Then
                            ' Actualizar el segundo objeto DataTable.
                            rows2(0)("Base") = row("Base")
                            rows2(0)("IVA") = row("IVA")
                            rows2(0)("Total") = row("Total")
                        End If
                    Next
    
                    ' Configuramos el ÚLTIMO adaptador de datos creado para
                    ' proceder a actualizar en la base de datos la tabla
                    ' Factura3 con los datos existentes en el segundo objeto
                    ' DataTable.
                    '
                    Dim cb As New SqlCeCommandBuilder(da)
                    cb.QuotePrefix = "["
                    cb.QuoteSuffix = "]"
                    da.UpdateCommand = cb.GetUpdateCommand()
    
                    Dim n As Integer = da.Update(dt2)
                    MessageBox.Show("Nº de registros actualizados: " & n.ToString())
    
                End Using
    
            Catch ex As Exception
                MessageBox.Show(ex.Message)
    
            End Try
    
        End Sub

    Obviamente, cuantos más registros existan para actualizar la operación tardará más tiempo, aunque tampoco es para "tirarse de los pelos", porque no creo que el cliente esté cada dos minutos consolidando datos, ¿o sí estará todo el rato consolidando datos? ;-)

    En fin, adapta el ejemplo a tus necesidades para ver si con ello sales del paso para consolidar los datos de la base de SQL Server Compact.


    Enrique Martínez Montejo
    [MS MVP - Visual Studio y Tecnologías de Desarrollo]

    Nota informativa: La información contenida en este mensaje, así como el código fuente incluido en el mismo, se proporciona «COMO ESTÁ», sin garantías de ninguna clase, y no otorga derecho alguno. Usted asume cualquier riesgo al poner en práctica, utilizar o ejecutar lo recomendado o sugerido en el presente mensaje.

    Si esta respuesta le ha resultado útil, recuerde marcarla como satisfactoria.

    Si usas Visual Basic .NET y deseas ser productivo y feliz, se inteligente y activa la instrucción
    Option Strict.






    jueves, 16 de febrero de 2017 18:47
    Moderador
  • Hola maestro:

    Nunca me has dejado sola y ya sabías que eso no lo sabía hacer, que nos conocemos.

    Bueno voy a preparar la cena y voy a meter después todo lo que me has indicado, eres único.

    Ya te diré como ha ido.

    Enrique, no cambies nunca maestro.

    Te agradezco infinitamente tu ayuda.

    Gracias amigo.

    Gemma

    jueves, 16 de febrero de 2017 19:29
  • Hola Enrique:

    Me he puesto hace un rato con este tema ya que antes no he podido.

    Te he de confesar que desgraciadamente no me aclaro con este tipo de consulta y no entiendo como adaptar la tuya a lo que necesito. Todo está en la misma tabla "Balances" adjunto la tabla y los tipos de campos de la misma.

    La he puesto tal como me has indicado pero no soy capaz de transformarla en lo que necesito. No se hacerlo.

    Es la única sql del programa que varía en Compact por culpa del maldito FROM y entonces ya me pierdo. Tu me estás indicando 2 tablas y no lo acabo de entender, discúlpame y no te enfades, pero es así, no se hacerlo.

    Yo te ruego como miles de veces que si puedes le hagas un vistazo a las imágenes adjuntas, y efectivamente se trata de sumar el Id_Empresa de la A01 con todos sus campos + la A02 con todos sus campos en la A03 que recoge la suma de la A02 y la A02 o las que sean., pueden ser mas empresas pero como mínimo 2.

    Bueno, estas son las imágenes y recuerda cuando puedas contestarme un correo personal que te he enviado esta mañana.

    En la imagen no sale la A01 pero es para hacerse una idea del problema.

    Lo siento maestro pero esta vez me ha costado seguirte en tus explicaciones y todo porque no acabo de entender la nueva mecánica que quieres hacer para el compact de la leche.

    En fin, gracias como siempre y un fuerte abrazo.

    Gemma

    viernes, 17 de febrero de 2017 12:22
  • "gemma_campillo" escribió:

    > Te he de confesar que desgraciadamente no me aclaro con este tipo de consulta y no
    > entiendo como adaptar la tuya a lo que necesito. Todo está en la misma tabla "Balances"
    > adjunto la tabla y los tipos de campos de la misma.

    Simplemente me limité a crear la consulta de selección de datos combinados de acuerdo a la sintaxis de la consulta de actualización que deseabas ejecutar en la base de SQL Compact y la cual mostraste en tu pregunta inicial:

    'SQL COMPACT
    '
    UPDATE BC SET BC.Ejer_01=B0.Ejer_01+B1.Ejer_01, BC.Ejer_02 = B0.Ejer_02 + B1.Ejer_02,
    BC.Ejer_03 = B0.Ejer_03 + B1.Ejer_03, BC.Ejer_04 = B0.Ejer_04 + B1.Ejer_04,BC.Ejer_05=B0.Ejer_05+B1.Ejer_05,
    BC.Ejer_06=B0.Ejer_06+B1.Ejer_06,BC.Ejer_07=B0.Ejer_07+B1.Ejer_07,BC.Ejer_08=B0.Ejer_08+B1.Ejer_08,
    BC.Ejer_09 = B0.Ejer_09 + B1.Ejer_09,BC.Ejer_10=B0.Ejer_10+B1.Ejer_10,BC.Ejer_11=B0.Ejer_11+B1.Ejer_11,
    BC.Ejer_12=B0.Ejer_12+B1.Ejer_12
    FROM Balances AS BC  INNER JOIN BALANCES AS B0 ON BC.[Cód_GC] = B0.[Cód_GC] AND BC.PlanConta = B0.PlanConta
    INNER Join BALANCES AS B1 ON BC.[Cód_GC] = B1.[Cód_GC] And BC.PlanConta = B1.PlanConta
    WHERE BC.PlanConta = 'PLAN 2007' AND BC.IdEmpresa = 'A03'  AND B0.idEmpresa='A01' AND B1.idEmpresa='A02'

    Si te soy sincero, me extrañaba que utilizaras la tabla BALANCES para combinar datos de la misma tabla, porque lo habitual es que cada Empresa tuviera su propia base de datos, y por tanto, su propia tabla Balance (en singular, no en plural). Pero ahora observo que en la misma tabla BALANCES tienes los datos de LOS BALANCES DE TODAS LAS EMPRESAS, y como no puedes hacer que la clave principal de la tabla se corresponda con el campo IdEmpresa (la cual tiene valores duplicados), te has "inventado" el campo autonumérico IdBalance para que existan registros únicos y poder hacer que ese campo forme la clave principal de la tabla Balances. :-(

    Para que yo me haga una idea del proceso de consolidación. Deseas sumar los 463 registros (o los que sean) de la empresa A01 con los mismos 463 registros de la empresa A02, y con el resultado obtenido actualizar también los 463 registros de la empresa A03, y todo ello con los datos existentes en la misma tabla Balances.

    Si es así, efectivamente no te sirve el ejemplo que te indiqué anteriormente, porque yo asumía que había una segunda tabla (Facturas3 en el ejemplo), pero resulta que todos los datos, tanto de selección como de actualización, están en la misma tabla Balances.

    Primero confírmame que yo me he enterado bien del proceso de consolidación, y segundo, te quisiera hacer las siguientes preguntas: ¿qué código ejecutas para consolidar los datos en la base de Access? ¿Has probado a ejecutar el mismo código que utilizas con Access para consolidar los datos de la base de SQL Compact? Por último, ¿todas las empresas tienen el mismo número de registros en la tabla Balances? 463 registros en la tabla Balances de la base de Access que dispongo. ¿El día de mañana podría aumentar o disminuir ese número de registros?


    Enrique Martínez Montejo
    [MS MVP - Visual Studio y Tecnologías de Desarrollo]

    Nota informativa: La información contenida en este mensaje, así como el código fuente incluido en el mismo, se proporciona «COMO ESTÁ», sin garantías de ninguna clase, y no otorga derecho alguno. Usted asume cualquier riesgo al poner en práctica, utilizar o ejecutar lo recomendado o sugerido en el presente mensaje.

    Si esta respuesta le ha resultado útil, recuerde marcarla como satisfactoria.

    Si usas Visual Basic .NET y deseas ser productivo y feliz, se inteligente y activa la instrucción
    Option Strict.



    viernes, 17 de febrero de 2017 18:06
    Moderador
  • Hola maestro:

    Estoy preocupada con esto, no lo acabo de entender y me fastidia mucho.

    Bueno, respondiendo a tus preguntas voy a probarlo con las misma sentencia de access y en segundo lugar me preguntas si todas las empresas tienen los mismos registros y la respuesta es si, para entendernos, el número de registros los marca el plan contable "PLAN 2007" en este caso, por lo tanto las 3 pertenecen al mismo plan contable y por ello tienen los mismos registros.

    Por otro lado "Para que yo me haga una idea del proceso de consolidación. Deseas sumar los 463 registros (o los que sean) de la empresa A01 con los mismos 463 registros de la empresa A02, y con el resultado obtenido actualizar también los 463 registros de la empresa A03, y todo ello con los datos existentes en la misma tabla Balances."

    Efectivamente es eso lo que hace la consolidación suma las 2 empresas y el resultado lo actualiza en la A03, actualizando todo lo que haya en la A03.Por último te adjunto el código de access que funciona perfectamente.

    Private Sub SetJoinsAndWhereForAccess()
    
            Dim sbJ As New StringBuilder()
            Dim sbW As New StringBuilder()
    
            Dim k As Integer = 0
            For Each item In m_clb.CheckedItems
                sbJ.AppendFormat(" INNER JOIN BALANCES AS B{0} ON (BC.[Cód_GC] = B{0}.[Cód_GC]) AND (BC.PlanConta = B{0}.PlanConta))", k)
                sbW.AppendFormat(" AND B{0}.idEmpresa='{1}'", k, m_clb.CheckedItems(k))
                k += 1
            Next
    
            ' Eliminar el último paréntesis de cierre de la sintaxis INNER JOIN
            '
            Dim index As Integer = sbJ.ToString().LastIndexOf(")"c)
            sbJ.Remove(index, 1)
    
            m_joins = sbJ.ToString()
            m_where = sbW.ToString()
    
        End Sub
    
    '///////////////////////////////////////////////////
    
     Public Function UpdateForAccess() As String
    
            ' Paréntesis de apertura
            Dim parentesis As String = New String("("c, m_clb.CheckedItems.Count - 1)
    
            Return String.Format("UPDATE {0}Balances AS BC {1} SET {2} WHERE BC.PlanConta = '{3}' AND BC.IdEmpresa = '{4}' {5}",
                                 parentesis, m_joins, m_fields, m_plan, m_empresa, m_where)
    
        End Function
    
    

    Te he de comentar que esta como tantas de las sentencias "complicadas" has sido tu el que siempre me has dado la solución.

    Voy a probar el access a ver si va. Te digo algo.

    Muchas gracias querido maestro.

    Gemma

    viernes, 17 de febrero de 2017 18:28
  • "gemma_campillo" escribió:

    > el número de registros los marca el plan contable "PLAN 2007"

    Sí, pero en la base de datos que yo tengo, figura el valor "COLOMBIA" en el campo PlanConta de la tabla Balances. ¿Los mismos registros tiene el Plan Contable de 2007 de España que el supuesto Plan Contable de Colombia?

    > Voy a probar el access a ver si va. Te digo algo.

    Pruébalo porque yo entiendo que debería de funcionar con SQL Compact, ya que parece ser que has pensado que SQL Compact es como SQL Server y no es del todo igual, ya que la referencia SQL para SQL Server Compact es un subconjunto del lenguaje Transact-SQL de SQL Server.

    Diferencias entre SQL Server Compact y SQL Server


    Enrique Martínez Montejo
    [MS MVP - Visual Studio y Tecnologías de Desarrollo]

    Nota informativa: La información contenida en este mensaje, así como el código fuente incluido en el mismo, se proporciona «COMO ESTÁ», sin garantías de ninguna clase, y no otorga derecho alguno. Usted asume cualquier riesgo al poner en práctica, utilizar o ejecutar lo recomendado o sugerido en el presente mensaje.

    Si esta respuesta le ha resultado útil, recuerde marcarla como satisfactoria.

    Si usas Visual Basic .NET y deseas ser productivo y feliz, se inteligente y activa la instrucción
    Option Strict.



    viernes, 17 de febrero de 2017 18:34
    Moderador
  • Hola Enrique;

    Aplicando las sql de Select y Update de Access da también error.

    Bueno, gracias Enrique.

    Gemma

    viernes, 17 de febrero de 2017 18:40
  • No me pongas código de Visual Basic porque no estoy yo ahora para "adivinanzas". ;-)

    Escribe la consulta SQL completa final que se ejecuta en la base de datos de Access.


    Enrique Martínez Montejo
    [MS MVP - Visual Studio y Tecnologías de Desarrollo]


    viernes, 17 de febrero de 2017 18:58
    Moderador
  • Hola Enrique:

    Este es el código de Access, probado con Access y funcionando perfectamente.

    Te pongo la consulta final que hay en el cmd.ExecuteNonQuery

    UPDATE (Balances AS BC  INNER JOIN BALANCES AS B0 ON (BC.[Cód_GC] = B0.[Cód_GC]) AND (BC.PlanConta = B0.PlanConta)) INNER JOIN BALANCES AS B1 ON (BC.[Cód_GC] = B1.[Cód_GC]) AND (BC.PlanConta = B1.PlanConta) SET BC.Ejer_01=B0.Ejer_01+B1.Ejer_01,BC.Ejer_02=B0.Ejer_02+B1.Ejer_02,BC.Ejer_03=B0.Ejer_03+B1.Ejer_03,BC.Ejer_04=B0.Ejer_04+B1.Ejer_04,BC.Ejer_05=B0.Ejer_05+B1.Ejer_05,BC.Ejer_06=B0.Ejer_06+B1.Ejer_06,BC.Ejer_07=B0.Ejer_07+B1.Ejer_07,BC.Ejer_08=B0.Ejer_08+B1.Ejer_08,BC.Ejer_09=B0.Ejer_09+B1.Ejer_09,BC.Ejer_10=B0.Ejer_10+B1.Ejer_10,BC.Ejer_11=B0.Ejer_11+B1.Ejer_11,BC.Ejer_12=B0.Ejer_12+B1.Ejer_12 WHERE BC.PlanConta = 'PLAN 2007' AND BC.IdEmpresa = '008'  AND B0.idEmpresa='001' AND B1.idEmpresa='005'

    Un abrazo y gracias

    Gemma

    viernes, 17 de febrero de 2017 19:20
  • He modificado el ejemplo que te indiqué más arriba para ver si así puedes actualizar los datos de la tabla Balances como resultado de la consolidación de dos empresas, porque digo yo que como mucho serán dos empresas, o por el contrario pueden ser 3, 10, 20 empresas cuyos datos se consoliden a la misma vez.

        Private Sub Button1_Click(sender As Object, e As EventArgs) Handles Button1.Click
    
            Try
                ' Configuramos la conexión con la base de datos de SQL Compact
                '
                Using cnn As New SqlCeConnection(cadenaConexionSqlServerCe)
    
                    ' Obtener un objeto DataTable como resultado de sumar
                    ' los campos de los ejercicios correspondientes a las
                    ' dos empresas que deseamos consolidar, ordenados de
                    ' manera ascendente por el campo Cód_GC de la tabla.
                    '
                    Dim dt1 As New DataTable()
                    Dim cmd As SqlCeCommand = cnn.CreateCommand()
                    cmd.CommandText = "SELECT BC.[Cód_GC], (BC.Ejer_01+B0.Ejer_01) AS Ej01, ([BC].[Ejer_02]+[B0].[Ejer_02]) AS Ej02," &
                        "([BC].[Ejer_03]+[B0].[Ejer_03]) AS Ej03, ([BC].[Ejer_04]+[B0].[Ejer_04]) AS Ej04," &
                        "([BC].[Ejer_05]+[B0].[Ejer_05]) AS Ej05, ([BC].[Ejer_06]+[B0].[Ejer_06]) AS Ej06," &
                        "(BC.Ejer_07+B0.Ejer_07) AS Ej07, ([BC].[Ejer_08]+[B0].[Ejer_08]) AS Ej08," &
                        "([BC].[Ejer_09]+[B0].[Ejer_09]) AS Ej09, ([BC].[Ejer_10]+[B0].[Ejer_10]) AS Ej10," &
                        "([BC].[Ejer_11]+[B0].[Ejer_11]) AS Ej11, ([BC].[Ejer_12]+[B0].[Ejer_12]) AS Ej12 " &
                        "FROM Balances AS BC INNER JOIN Balances AS B0 ON BC.[Cód_GC] = B0.[Cód_GC] " &
                        "WHERE BC.PlanConta = 'PLAN 2007' AND BC.IdEmpresa='A01' AND B0.IdEmpresa='A02' " &
                        "ORDER BY B0.[Cód_GC]"
    
                    Dim da As New SqlCeDataAdapter(cmd)
                    da.Fill(dt1)
    
                    ' Obtener un objeto DataTable con los datos de la empresa
                    ' donde deseamos reflejar los datos consolidados, ordenados
                    ' los registros por el campo que Cód_GC.
                    '
                    Dim dt2 As New DataTable()
                    cmd = cnn.CreateCommand()
                    cmd.CommandText =
                        "SELECT * FROM Balances " &
                        "WHERE PlanConta = 'PLAN 2007' AND IdEmpresa='A03' " &
                        "ORDER BY [Cód_GC]"
    
                    da = New SqlCeDataAdapter(cmd)
                    da.Fill(dt2)
    
                    ' Conforme recorremos los registros del primer objeto
                    ' DataTable vamos actualizando los datos del segundo
                    ' objeto DataTable.
                    '
                    For Each row As DataRow In dt1.Rows
                        Dim rows2 As DataRow() = dt2.Select(String.Format("Cód_GC = '{0}'", row("Cód_GC")))
                        If (rows2.Length > 0) Then
                            ' Actualizar la tabla temporal 
                            rows2(0)("Ejer_01") = row("Ej01")
                            rows2(0)("Ejer_02") = row("Ej02")
                            rows2(0)("Ejer_03") = row("Ej03")
                            rows2(0)("Ejer_04") = row("Ej04")
                            rows2(0)("Ejer_05") = row("Ej05")
                            rows2(0)("Ejer_06") = row("Ej06")
                            rows2(0)("Ejer_07") = row("Ej07")
                            rows2(0)("Ejer_08") = row("Ej08")
                            rows2(0)("Ejer_09") = row("Ej09")
                            rows2(0)("Ejer_10") = row("Ej10")
                            rows2(0)("Ejer_11") = row("Ej11")
                            rows2(0)("Ejer_12") = row("Ej12")
                        End If
                    Next
    
                    ' Configuramos el ÚLTIMO adaptador de datos creado para
                    ' proceder a actualizar en la base de datos la tabla
                    ' Balances con los datos existentes en el segundo objeto
                    ' DataTable.
                    '
                    Dim cb As New SqlCeCommandBuilder(da)
                    cb.QuotePrefix = "["
                    cb.QuoteSuffix = "]"
                    da.UpdateCommand = cb.GetUpdateCommand()
    
                    Dim n As Integer = da.Update(dt2)
                    MessageBox.Show("Nº de registros actualizados: " & n.ToString())
    
                End Using
    
            Catch ex As Exception
                MessageBox.Show(ex.Message)
    
            End Try
    
        End Sub
    

    La he probado y parece ser que funciona. Como podrás observar, el procedimiento es el mismo: primero seleccionamos un objeto DataTable donde los valores de los campos ya están sumados, y después vamos actualizando, uno a uno, los registros de la empresa donde deseas que aparezcan los datos consolidados.

    Es como si ejecutáramos una consulta UPDATE por cada registro que deseamos actualizar, pero que en lugar de hacerlo nosotros, se encargará de ello el método Update del adaptador de datos que hemos configurado.


    Enrique Martínez Montejo
    [MS MVP - Visual Studio y Tecnologías de Desarrollo]

    Nota informativa: La información contenida en este mensaje, así como el código fuente incluido en el mismo, se proporciona «COMO ESTÁ», sin garantías de ninguna clase, y no otorga derecho alguno. Usted asume cualquier riesgo al poner en práctica, utilizar o ejecutar lo recomendado o sugerido en el presente mensaje.

    Si esta respuesta le ha resultado útil, recuerde marcarla como satisfactoria.

    Si usas Visual Basic .NET y deseas ser productivo y feliz, se inteligente y activa la instrucción
    Option Strict.

    • Marcado como respuesta gemma_campillo sábado, 18 de febrero de 2017 8:59
    sábado, 18 de febrero de 2017 8:17
    Moderador
  • Hola Enrique:

    Va perfecto. Con las empresas A01 y A02, consolidadas en la A03.

    Es una maravilla.

    Evidentemente te doy las gracias al un problemón que tenía y no sabía como solucionarlo. Ahora ya está. voy a poner variables en los códigos de empresa para que puede escoger cualquiera de ellas, y claro el usuario puede querer consolidar dos o más empresas, si te parece, voy a hacer unos if para 3, 4 y 5 empresas que no creo que haya alguien que quiera consolidar mas.

    LO que hago también es dejar lo que había para Access y SqlServer que van perfectas.

    Bueno maestro, te reitero mi más profundo agradecimiento a tu interés.

    Un fuerte abrazo querido amigo.

    Gemma


    sábado, 18 de febrero de 2017 8:59