SQL Server Select sum más eficiente

B

Hola a todos. De nuevo busco vuestro consejo para intentar optimizar una consulta que me muestra varios campos relacionados con el stock de un almacén.

Digamos que tengo una tabla como la siguiente, y quiero obtener el stock, la cantidad entregada, y las salidas.

El resultado de la consulta debería devolverme esto:

Stock --> 7
Entegado --> 8
Salidas --> 1

Y la sentencia que uso es esta:

SELECT 
	gen.Producto, 
	gen.Descripcion, 
	COALESCE(SUM(st.Cantidad), 0) AS Stock,
	Entregado = (SELECT COALESCE(SUM(ent.Cantidad), 0) FROM [ALMACEN_Importar_productos] ent WHERE ent.Producto = gen.Producto AND ent.Almacen = 'verde' AND ent.Positivo = 1),
	Salidas = -(SELECT COALESCE(SUM(sal.Cantidad), 0) FROM [ALMACEN_Importar_productos] sal WHERE sal.Producto = gen.Producto AND sal.Almacen = 'verde' AND sal.Positivo = 0)
FROM [ALMACEN_Importar_productos] gen
WHERE gen.Almacen = 'verde'
GROUP BY gen.Producto, gen.Descripcion

La sentencia funciona, pero quisiera informarme sobre si hay una forma mejor, más elegante o más rápida de obtener los datos.

Muchas gracias a todos y un saludo.

Soltrac

La teoría de base de datos nos dice que no debemos tener campos duplicados y esas mierdas. La práctica nos dice que los triggers se inventaron para algo.

Quieres evitar problema de rendimiento? Usa triggers, cada vez que agregues un dato a esa tabla modifica con un trigger en la DB unos valores fijos y consulta esos valores fijos. Ahora no tendrás problemas de rendimiento, pero en el futuro sí.

Otra cosa es que necesites saber los movimientos hechos en un rango de fechas, ahí poco vas a poder hacer. Podrías crear unas vistas para los movimientos positivos y negativos y mostrar datos, evitando los SELECT encadenados, a ver si mejora algo.

1 respuesta
CCiRviNe

Podrías hacer un SUM(IIF/CASE WHEN) en lugar de varios SELECT. Creo que en SQL Server es el CASE WHEN y sería algo como:

SELECT
...
COALESCE(SUM(CASE WHEN gen.Positivo = 1 THEN Cantidad Else 0 End), 0) AS Entregado
...
FROM
...
1 respuesta
B

#2 Es una tabla que tiene millones de registros, y se puede sacar el stock total o en un rango de fechas, por lo que no puedo tener campos fijos, pero gracias por el consejo.

#3 tengo que sacar los tres valores, cuando es positivo, cuando es negativo y el stock para cada producto, no puedo hacer un case

Gracias.

2 respuestas
Soltrac

#4 Pues la forma más eficiente que se me ocurre es la siguiente:

En cada registro vas guardando el total acumulado, así puedes hacer un TOP 1 a una fecha determinada. Por supuesto, creo que tendrás que indexar la fecha del movimiento para q ese TOP 1 sea más o menos rápido.

Sería algo así:

Fecha - Cantidad - Positivo - Entregado - Salido - Stock
------------------------------------------------------------------------
Bla       1               1            1                0          1
Bla2     3               1            4                0          4
Bla3     -2              0            4                2          2

Cuando hagas un TOP 1 WHERE Fecha <= Bla3 tendrás Entregado, salido y stock a esa fecha. Como te he dicho, indexando fecha.

1 respuesta
CCiRviNe

#4 en el ejemplo de #3 solo ponía el entregado (que es cuando es positivo), no te había puesto la solución completa que sería algo así:

SELECT gen.Producto, gen.Descripcion, 
        COALESCE(SUM(Cantidad), 0) AS Stock,
        COALESCE(SUM(CASE WHEN Positivo = 1 THEN Cantidad Else 0 End), 0) AS Entregado,
        COALESCE(SUM(CASE WHEN Positivo = 0 THEN -Cantidad Else 0 End), 0) AS Salidas
FROM [ALMACEN_Importar_productos] gen
WHERE gen.Almacen = 'verde'
GROUP BY gen.Producto, gen.Descripcion
1 respuesta
B

.

JuAn4k4

Tienes algún indice en la tabla ?

Yo diría de quitar la "descripción", intentar utilizar INT para los productos en lugar de dos VARCHARS (producto + descripción) y lo mismo para el almacén.

Y tener un indice en : Producto + Cantidad + Almacen, y obviar el "positivo" con cantidad>0 / cantidad<0

Además usar el case para sumar los positivos y los negativos por separado.

Usuarios habituales