Pregunta

Estoy tratando de ejecutar una consulta en SQL Server 2008 en una tabla donde algunos de los datos se ingresaron de manera inconsistente y tengo que manejar esto.

Ejemplo de datos de tabla:

OrderID   Qty   Price   MarkedUpTotal
1         10    1.00    11.00
1         -1    1.00    -1.10
1         -1    1.00    1.10

Tengo que manejar la situación en la que Qty es negativo pero MarkedUpTotal se ingresó como positivo.

Me gustaría ejecutar la siguiente consulta:

SELECT OrderID, SUM(Qty) as OrderTotalQty, 
        SUM(Qty*Price) as InternalCost,
        CASE WHEN Qty < 0 and MarkedUpTotal > 0 
             THEN sum(-1*MarkedUpTotal) 
             ELSE SUM(MarkedUpTotal) END as ClientCost  
    FROM OrderItems 
    GROUP BY OrderID

Sin embargo, aparece el siguiente error cuando ejecuto esta consulta:

La cantidad de columna no es válida en la lista de selección porque no está contenida ni en una función agregada ni en la cláusula GROUP BY.

La columna MarkedUpTotal no es válida en la lista de selección porque no está contenida ni en una función agregada ni en la cláusula GROUP BY.

Deseo el siguiente resultado:

OrderID    OrderTotalQty   InternalCost   ClientCost
1          8               8.00           8.80

Me parece extraño que deba GROUP BY Qty y MarkedUpTotal cuando solo se usan condicionalmente por la declaración CASE. Si elimino la última selección (la declaración CASE), la consulta se ejecuta bien y no requiere Cantidad o Precio para estar en GROUP BY.

¿Por qué SQL requiere esto? ¿Hay una sola consulta que pueda lograr lo anterior?

Actualmente estoy resolviendo el problema usando una tabla temporal. Modifico el MarkedUpTotal de cada entrada si es necesario y luego hago un SUM simple (MarkedUpTotal) en la consulta principal de la tabla temporal.

¿Fue útil?

Solución

SELECT OrderID, SUM(Qty) as OrderTotalQty, 
        SUM(Qty*Price) as InternalCost,
        SUM(CASE WHEN Qty < 0 and MarkedUpTotal > 0 
             THEN -1*MarkedUpTotal
             ELSE MarkedUpTotal) END as ClientCost  
    FROM OrderItems 
    GROUP BY OrderID

La razón por la que da error es porque lo estás SUMANDO dentro del CASO, lo que devolverá 1 valor afuera. Para SELECT con GROUP BY, parecerá que está pasando un valor numérico (que podría ser una constante o proviene de otra fuente) como una columna.

Piense en su instrucción SQL, similar a esto

SELECT OrderID, SUM(Qty) as OrderTotalQty, 
        SUM(Qty*Price) as InternalCost,
        CASE WHEN Qty < 0 and MarkedUpTotal > 0 
             THEN 10
             ELSE 20 END as ClientCost  
    FROM OrderItems 
    GROUP BY OrderID

Ahora esto devuelve una nueva columna (ClientCost), que no utiliza ninguna agregación.
Entonces, le pide que use eso en la expresión GROUP BY.

Otros consejos

Tenga en cuenta que el resultado de una instrucción GROUP BY, o de una declaración en la que una o las columnas utilizan una función agregada, tiene cada fila que contiene un resumen de otras filas.

La expresión CASE que está utilizando depende de valores de filas individuales en lugar de resúmenes; solo puede hacer referencia a valores no agregados (es decir, valores de una sola fila) en una función agregada o en la cláusula WHERE, por lo que la solución implicaría colocar su CASO dentro de una función agregada, en este caso su SUMA.

El error es sobre esta parte. ¿Qué valor de fila de cantidad debe usar SQL Server?

CASE WHEN Qty < 0 and MarkedUpTotal > 0 
    THEN sum(-1*MarkedUpTotal) 
    ELSE SUM(MarkedUpTotal) 
END as ClientCost

Puedes reescribirlo como:

sum(CASE WHEN Qty < 0 and MarkedUpTotal > 0 
    THEN sum(-1*MarkedUpTotal) 
    ELSE SUM(MarkedUpTotal) 
END as ClientCost)

O:

CASE WHEN sum(Qty) < 0 and sum(MarkedUpTotal) > 0 
    THEN sum(-1*MarkedUpTotal) 
    ELSE SUM(MarkedUpTotal) 
END as ClientCost

Dependiendo de lo que quieras decir :)

Hazlo así:

SELECT OrderID, SUM(Qty) as OrderTotalQty, 
        SUM(Qty*Price) as InternalCost,
        sum(CASE WHEN Qty < 0 and MarkedUpTotal > 0 
             THEN -1*MarkedUpTotal 
             ELSE MarkedUpTotal END) as ClientCost  
    FROM OrderItems 
    GROUP BY OrderID
  

Me parece extraño que deba GRUPO   POR Qty y MarkedUpTotal cuando están   solo siendo usado condicionalmente por el   Declaración de CASO.

He resaltado el error a continuación:

SELECT OrderID, SUM(Qty) as OrderTotalQty, 
        SUM(Qty*Price) as InternalCost,
        CASE WHEN Qty < 0 and MarkedUpTotal > 0   -- BOOM!!!!!!
             THEN sum(-1*MarkedUpTotal) 
             ELSE SUM(MarkedUpTotal) END as ClientCost  
    FROM OrderItems 
    GROUP BY OrderID

El servidor SQL no sabe cómo evaluar CASE WHEN Qty < 0 and MarkedUpTotal > 0. Tiene 3 valores diferentes para estos registros en su tabla, lo que normalmente no es un problema, pero dado que está agrupando sus registros, la expresión no tiene sentido ya que el servidor SQL no sabe cuál de los tres valores usar cuando evalúa la expresión de caso, por lo que arroja los errores de análisis poco amigables para el usuario vistos en el OP.

Todas las sugerencias de código en este hilo proporcionan una solución.

Licenciado bajo: CC-BY-SA con atribución
No afiliado a StackOverflow
scroll top