none
Consulta select da resultado diferente en Vista que en Tabla aún con los mismos datos RRS feed

  • Pregunta

  • Hola a todos!

    Como dice la pregunta, inicialmente creí que tenía algún error en el select ya que no me daba los resultados esperados. Más sin embargo me llevé una sorpresa al crear una nueva tabla (Ya no una vista sino una tabla) donde capturé los mismos datos que tenía la vista y el resultado de la columna Saldo es el correcto.

    La columna saldo se calcula a partir de los valores de la columna Monto y se suma si la columna Num tiene un 1 o se resta si tiene un 2. Va haciendo el cálculo agrupado por ID.

    Les comparto mi código de la consulta así como el resultado que obtengo en cada tabla. Agradecería sus comentarios sobre si debo realizar algo adicional en la vista. Me parece muy extraño el comportamiento.

    Uso SQL Server 2008 r2

    SELECT DE TABLA VISTA

    SELECT *
    FROM Vista A
    OUTER APPLY (SELECT SUM(CASE WHEN Num = 2 THEN -1 ELSE 1 END * MontoUsar) SALDO
                 FROM Vista
                 WHERE IDCTA = A.IDCTA
                 AND INDICE <= A.INDICE) B;

    RESULTADO (DONDE ESTÁ SEÑALADO EL 200 DEBERÍA IR UN 0)

    SELECT DE TABLA

    SELECT *
    FROM dbo.Tabla A
    OUTER APPLY (SELECT SUM(CASE WHEN NUM = 2 THEN -1 ELSE 1 END * MONTO) SALDO
                 FROM dbo.Tabla
                 WHERE ID = A.ID
                 AND INDICE <= A.INDICE) B;

    RESULTADO CORRECTO

    miércoles, 25 de abril de 2018 15:08

Todas las respuestas

  • ¿Puede ser que haya alguna diferencia en los tipos de datos entre la tabla y la vista? Por ejemplo, que algún campo que era numérico en la vista se haya exportado como varchar a la tabla. En la imagen no se notaría, pero afectaría, por ejemplo, al comportamiento del <=.

    En cualquier caso, es una forma tremendamente ineficiente de calcular el saldo. Con una tabla grande se volverá lentísimo. La razón es que por cada fila tiene que repetir la suma de todas las filas anteriores, en lugar de ir arrastrando la suma y añadirle cada fila nueva. Este es uno de los poquísimos casos excepcionales en los que es preferible usar un cursor en lugar de la lógica declarativa. Pero si tienes un SQL Server razonablemente moderno (creo que el mínimo es 2012) entonces lo ideal es hacerlo con la cláusula OVER, que funciona perfectamente tanto sobre tablas como sobre vistas y tiene buen rendimiento.

    miércoles, 25 de abril de 2018 21:08
  • jueves, 26 de abril de 2018 12:15
  • Agradezco sus respuestas. Efectivamente coincido contigo Alberto sobre que debe haber una forma más práctica de calcular el campo saldo. En este momento la tabla nunca llegará a más de 20 registros mensuales y se renovará cada nuevo mes, por lo tanto puede ser útil esta técnica que estoy usando.

    Ya pude resolver el detalle, aunque sigo sin encontrarle mucha lógica ya que además de que los registros son idénticos en la vista como en la tabla también los son el tipo de datos de cada campo.

    Lo que hice en la tabla Vista fue modificar el consecutivo de la columna índice, de tal forma que se reinicie en base al ID. Este es el código que utilicé:

    SELECT top 99.999999 percent
            ROW_NUMBER() OVER(PARTITION BY ID ORDER BY NUM) [INDICE],
            *FROM Tabla ORDER BY ID

    Volví a utilizar la consulta select y el resultado fue justo el que esperaba.

    Agradezco sus comentarios.

    jueves, 26 de abril de 2018 14:59
  • Elimina las clausulas TOP 99.999 y ORDER BY en la definicion de la vista.  No tienen ningun sentido que esten ahi.

    Me pregunto si la combinacion de columnas (ID, NUM) puede ser usada para identificar unicamente una fila en la tabla?

    De ser asi no necesitas enumerar las filas con ROW_NUMBER y si no entonces deberas buscar una columna mas para romper los empates, de lo contrario no sera determinista.

    En la data de ejemplo que posteastes originalmente, las filas:

    id    num    monto
    4     2        0
    4     2        100
    4     2        140
    4     2        1000

    pueden cambiar su enumeracion entre una corrida y la otra, puesto que usar
    OVER(PARTITION BY id ORDER BY num) no sera determinista y podria ser cualquiera de estos resultados:

    id    num    monto
    4     2        100
    4     2        140
    4     2        0
    4     2        1000 

    id    num    monto
    4     2        1000
    4     2        100
    4     2        140
    4     2        0

    id    num    monto
    4     2        140
    4     2        1000
    4     2        0
    4     2        100

    ...


    AMB

    Some guidelines for posting questions...

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


    jueves, 26 de abril de 2018 15:23