none
Comparar la suma de dos tablas RRS feed

  • Pregunta

  • Hola comunidad espero que estén muy bien, necesito que me ayuden ya que es primera vez que me topo con este problema.

    Bueno tengo dos tablas, por ejemplo tabla1 y tabla2, ambas tablas se relacionan por 3 llaves, necesito rescatar el monto1 de la tabla1 y el monto2 de la tabla2.

    Si filtro por el año, mes y folio en la tabla1 puedo tener uno o muchos registros y lo mismo sucede en la tabla2

    Tabla1 (año  ,  mes  , folio , monto1  )

                 2017 ,      2       , 2     ,    30.000

                 2017 ,      2       , 2     ,    25.000

    Tabla2 (año  ,  mes  , folio , monto2  )

                2017    ,  2        , 2          , 100.00

              2017      ,  2        , 2          , 110.00

              2017      ,  2        , 2          , 150.00


    Bueno en la tabla1 tengo 2 registro y el monto1 total serial 55.000 y en la tabla2 el monto2 total seria de 360.000,

    entonces busco una Query que me compare los montos de ambas tablas y si son distintos que lo muestre... 

    A modo de ejemplo hice esta consulta pero no me resulta ya que el tot1 se suma la misma cantidad de registro que tenga la tabla2, se entiende? (es decir en vez de mostrarme 55.000 me muestra 165.000, se multiplica por 3 por que la tabla2 tiene 3 registros.)

    Busco la forma que sume de manera independiente el monto de la tabla1 y el monto de la tabla2 y al final se compare los montos, me di a explicar bien?, o si tienen otra forma que sea mejor quizas con subconsultas y me explique se los agradecería mucho.

    Ejempo de query

    select Sum(a.monto1) as tot1, Sum(b.monto2) as tot2
    
    From Tabla1 a
    
    Inner Join Tabla2 b
    
    On
    
    a.año = b.año and
    
    a.mes = b.mes and
    
    a.folio = b.folio 
    
    Where
    
    a.año = 2017 and
    
    a.mes = 2 and
    
    a.folio = 2;

    Saludos.



    • Editado Tronxs martes, 22 de agosto de 2017 19:35
    martes, 22 de agosto de 2017 19:28

Respuestas

  • Intenta combinando por los conjuntos agrupados, por ejemplo

    SELECT t1.*, t2.*
    FROM
        (SELECT año, mes, folio, SUM(monto1) Monto1 FROM Tabla1 GROUP BY año, mes, folio) t1
        LEFT JOIN 
        (SELECT año, mes, folio, SUM(monto2) Monto2 FROM Tabla2 GROUP BY año, mes, folio) t2
    	   ON t1.año = t2.año AND t1.mes = t2.mes AND t1.folio = t2.folio AND t1.Monto1 <> t2.Monto2
    GO


    Nuestra profesión exige tener pasión por resolver problemas de una manera óptima y eficiente.
    • Marcado como respuesta Tronxs martes, 22 de agosto de 2017 20:36
    martes, 22 de agosto de 2017 19:39
  • Hazlo exactamente como lo comentastes.

    with tot_tabla1 as (
    select año, mes, folio, sum(monto1) as total_monto1
    from tabla1
    group by año, mes, folio
    )
    , tot_tabla1 as (
    select año, mes, folio, sum(monto2) as total_monto2
    from tabla2
    group by año, mes, folio
    )
    select
        coalesce(T1.año, T2.año) as año,
        coalesce(T1.mes, T2.mes) as mes,
        coalesce(T1.folio, T2.folio) as folio,
        isnull(T1.total_monto1, 0) as total_monto1,
        isnull(T2.total_monto2, 0) as total_monto2,
        case when isnull(T1.total_monto1, 0) <> isnull(T2.total_monto2, 0) then 'D' else 'I' end as dif_flag
    from tot_tabla1 as T1 full outer join tot_tabla2 as T2
    on T1.año = T2.año and T1.mes = T2.mes and T1.folio = T2.folio;

    Usar un FULL OUTER JOIN te permitira ver filas en una tabla no presentes en la otra.

    Tambien puedes usar EXCEPT para identificar por separado.

    -- totales en tabla1 no machan fila en tabla2
    (
    select año, mes, folio, sum(monto1) as total_monto
    from tabla1
    group by año, mes, folio
    )
    EXCEPT
    (
    select año, mes, folio, sum(monto2) as total_monto
    from tabla2
    group by año, mes, folio
    );

    -- totales en tabla2 no machan fila en tabla1
     (
    select año, mes, folio, sum(monto2) as total_monto
    from tabla2
    group by año, mes, folio
    )
    EXCEPT
    (
    select año, mes, folio, sum(monto1) as total_monto
    from tabla1
    group by año, mes, folio
    );


    AMB

    Some guidelines for posting questions...

    AYÚDANOS A AYUDARTE, guía básica de consejos para formular preguntas


    • Editado HunchbackMVP martes, 22 de agosto de 2017 19:44
    • Marcado como respuesta Tronxs martes, 22 de agosto de 2017 20:36
    martes, 22 de agosto de 2017 19:39

Todas las respuestas

  • Intenta combinando por los conjuntos agrupados, por ejemplo

    SELECT t1.*, t2.*
    FROM
        (SELECT año, mes, folio, SUM(monto1) Monto1 FROM Tabla1 GROUP BY año, mes, folio) t1
        LEFT JOIN 
        (SELECT año, mes, folio, SUM(monto2) Monto2 FROM Tabla2 GROUP BY año, mes, folio) t2
    	   ON t1.año = t2.año AND t1.mes = t2.mes AND t1.folio = t2.folio AND t1.Monto1 <> t2.Monto2
    GO


    Nuestra profesión exige tener pasión por resolver problemas de una manera óptima y eficiente.
    • Marcado como respuesta Tronxs martes, 22 de agosto de 2017 20:36
    martes, 22 de agosto de 2017 19:39
  • Hazlo exactamente como lo comentastes.

    with tot_tabla1 as (
    select año, mes, folio, sum(monto1) as total_monto1
    from tabla1
    group by año, mes, folio
    )
    , tot_tabla1 as (
    select año, mes, folio, sum(monto2) as total_monto2
    from tabla2
    group by año, mes, folio
    )
    select
        coalesce(T1.año, T2.año) as año,
        coalesce(T1.mes, T2.mes) as mes,
        coalesce(T1.folio, T2.folio) as folio,
        isnull(T1.total_monto1, 0) as total_monto1,
        isnull(T2.total_monto2, 0) as total_monto2,
        case when isnull(T1.total_monto1, 0) <> isnull(T2.total_monto2, 0) then 'D' else 'I' end as dif_flag
    from tot_tabla1 as T1 full outer join tot_tabla2 as T2
    on T1.año = T2.año and T1.mes = T2.mes and T1.folio = T2.folio;

    Usar un FULL OUTER JOIN te permitira ver filas en una tabla no presentes en la otra.

    Tambien puedes usar EXCEPT para identificar por separado.

    -- totales en tabla1 no machan fila en tabla2
    (
    select año, mes, folio, sum(monto1) as total_monto
    from tabla1
    group by año, mes, folio
    )
    EXCEPT
    (
    select año, mes, folio, sum(monto2) as total_monto
    from tabla2
    group by año, mes, folio
    );

    -- totales en tabla2 no machan fila en tabla1
     (
    select año, mes, folio, sum(monto2) as total_monto
    from tabla2
    group by año, mes, folio
    )
    EXCEPT
    (
    select año, mes, folio, sum(monto1) as total_monto
    from tabla1
    group by año, mes, folio
    );


    AMB

    Some guidelines for posting questions...

    AYÚDANOS A AYUDARTE, guía básica de consejos para formular preguntas


    • Editado HunchbackMVP martes, 22 de agosto de 2017 19:44
    • Marcado como respuesta Tronxs martes, 22 de agosto de 2017 20:36
    martes, 22 de agosto de 2017 19:39
  • Muchas gracias por su respuesta y tiempo

    Deje así la Query y me sirvió por lo que se ve.

    SELECT t1.*, t2.*
    FROM
        (SELECT año, mes, folio, SUM(monto1) Monto1 FROM Tabla1 GROUP BY año, mes, folio) t1
        INNER JOIN 
        (SELECT año, mes, folio, SUM(monto2) Monto2 FROM Tabla2 GROUP BY año, mes, folio) t2
           ON 
           t1.año     = t2.año     AND 
           t1.mes     = t2.mes     AND 
           t1.folio   = t2.folio   AND 
           t1.Monto1 <> t2.Monto2
           Where
            t1.ano   = 2017 and
            t1.mes   = 2    and
            t1.folio = 2 

    martes, 22 de agosto de 2017 20:36
  • Realiza el filtro en la primera subconsulta para evitar la combinación de conjuntos grandes.

    SELECT t1.*, t2.*
    FROM
        (SELECT año, mes, folio, SUM(monto1) Monto1 FROM Tabla1 
        WHERE año = 2017 AND mes = 2 AND folio = 2  GROUP BY año, mes, folio) t1
        LEFT JOIN 
        (SELECT año, mes, folio, SUM(monto2) Monto2 FROM Tabla2 GROUP BY año, mes, folio) t2
    	   ON t1.año = t2.año AND t1.mes = t2.mes AND t1.folio = t2.folio AND t1.Monto1 <> t2.Monto2
    GO


    Nuestra profesión exige tener pasión por resolver problemas de una manera óptima y eficiente.
    martes, 22 de agosto de 2017 21:39
  • Gracias por tu respuesta.

    Willams como se llama este tipo de consultas? que tipo de conceptos esta en juego?

    Saludos.

    miércoles, 23 de agosto de 2017 11:58
  • como se llama este tipo de consultas? 

    No se a cual te refieres pero no es mas que un JOIN (inner / outer) entre dos tablas derivadas (sub-query de agrupacion).

    que tipo de conceptos esta en juego?

    No creo tener la informacion necesaria sobre la relacion entre ambas tablas pero parece ser que es una relacion de muchos a muchos (año, mes, folio) y por lo tanto se debera agrupar primero por estas columnas para lograr una relacion de uno a uno/ninguno, de lo contrario estariamos duplicando data en ambos lados.

    Ejemplo:

    select * from (values(1), (1)) as T1(col1) inner join (values(1), (1), (1)) as T2(col1) on T1.col1 = T2.col2;

    Este query nos daria seis filas como resultado.

    En cuanto a poner el filtro en el subquery o fuera, pues en tu caso (inner join) no habra diferencia y el optimizador empujara esos filtros lo mas cerca posible de la lectura, aunque no se pierde nada con ser redundante y darle al optimizador mas informacion sobre lo que se desea (filtrar en ambos subqueries).  Puedes comparar el plan de ejecucion de ambas sentencias.

    SELECT
        t1.*, t2.*
    FROM
        (SELECT año, mes, folio, SUM(monto1) Monto1 FROM Tabla1 GROUP BY año, mes, folio) AS t1
        INNER JOIN 
        (SELECT año, mes, folio, SUM(monto2) Monto2 FROM Tabla2 GROUP BY año, mes, folio) AS t2
        ON 
        t1.año     = t2.año     AND 
        t1.mes     = t2.mes     AND 
        t1.folio   = t2.folio   AND 
        t1.Monto1 <> t2.Monto2
    WHERE
        t1.ano   = 2017 AND
        t1.mes   = 2    AND
        t1.folio = 2	AND
        t2.ano   = 2017 AND
        t2.mes   = 2    AND
        t2.folio = 2;
    
    SELECT
        t1.*, t2.*
    FROM
        (SELECT año, mes, folio, SUM(monto1) Monto1 FROM Tabla1 WHERE t1.ano = 2017 AND t1.mes = 2 AND t1.folio = 2 GROUP BY año, mes, folio) AS t1
        INNER JOIN 
        (SELECT año, mes, folio, SUM(monto2) Monto2 FROM Tabla2 WHERE t2.ano = 2017 AND t2.mes = 2 AND t2.folio = 2 GROUP BY año, mes, folio) AS t2
        ON 
        t1.año     = t2.año     AND 
        t1.mes     = t2.mes     AND 
        t1.folio   = t2.folio
    WHERE
        t1.Monto1 <> t2.Monto2;
    GO


    AMB

    Some guidelines for posting questions...

    AYÚDANOS A AYUDARTE, guía básica de consejos para formular preguntas


    • Editado HunchbackMVP miércoles, 23 de agosto de 2017 13:46
    miércoles, 23 de agosto de 2017 12:32
  • ¿cómo se llama este tipo de consultas? ¿qué tipo de conceptos está en juego?

    Para el caso que presentas se debía resumir los datos de las tablas 'Tabla1' y 'Tabla2' para luego combinar entre ambas por valores de columna únicos. Imagínate por un momento que tuvieses dos tablas conteniendo la información resumida, la consulta sería muy simple:

    SELECT t1.*, t2.*
    FROM
        Tabla1 t1
        INNER JOIN Tabla2 t2 ON t1.año = t2.año AND t1.mes = t2.mes AND t1.folio = t2.folio 
    	   AND t1.Monto1 <> t2.Monto2
    GO

    Pero como no es así tienes que "acomodar" primero los datos antes de realizar las operaciones de combinación, claro la "complejidad" de las subconsultas las pudiste haber abstraído en una vista o como valores en una tabla temporal, una variable de tipo table, etc., y luego combinar los resultados "de manera limpia" tal como el ejemplo, sin embargo para el caso puntual aparentemente bastaba crear "al vuelo" tablas derivadas y utilizarlas en la consulta. Pero ¿qué son tablas derivadas?, son subconsultas que van en el lado de la cláusula FROM a diferencia de las subconsultas que van en las cláusulas ON, WHERE, HAVING, etc. Lo mismo que una tabla derivada pudiste haber utilizado una CTE tal como propuso en su primera intervención Alejandro.


    Nuestra profesión exige tener pasión por resolver problemas de una manera óptima y eficiente.
    miércoles, 23 de agosto de 2017 17:14
  • Excelente gracias
    martes, 9 de marzo de 2021 16:01