Consulta SQL para ver artículos con baja rotación

Buenos y calurosos días desde España!.
Quería preguntarles si tienen alguna consulta para ver cuáles son los artículos con baja rotación.
No tengo muchos conocimientos de SQL y no sé por dónde empezar!
Gracias!!!

2 Me gusta

Gracias @SidV por la corrección!. Así será más fácil que alguien sepa qué estoy preguntando. :kissing_closed_eyes:

1 me gusta

Hola compañera.

Has revisado el informe “Informe de artículos inactivos”, la ayuda de Business nos dice que “Esta lista muestra todos los artículos que no aparecen en ninguno de los documentos de ventas seleccionados desde una fecha especificada.”

Pues @Gera_Mendez es que tengo un problema con ese informe, tanto para artículos como para interlocutores comerciales (o socios de negocio), y es que me saca códigos que sí están activos.

Por ejemplo, ahora mismo acabo de ejecutar ese informe para todos los artículos de mis almacenes, con fecha 01/01/17 y al abrirse la ventana con el resultado he marcado todos los tipos de documentos. Entiendo que eso quiere decir que le estoy pidiendo al sistema que me muestre todos los artículos que, desde el 1 de enero, no se han usado en cualquiera de esos documentos (ofertas de ventas, entregas, anticipos de clientes, pedidos, facturas de clientes). Sería así, verdad?.

Pues bien, me salen códigos de los que se ha hecho una entrada de pedido hace escasos 15 días

O es que las entradas/salidas de mercancía o las facturas de proveedores no se tienen en cuenta?. En cualquier caso, no me sirve este informe porque aparecen artículos que sí han tenido movimientos hacia dentro y hacia afuera de mis almacenes.

La ayuda nos dice que trabaja en función a ventas solamente.

En tu caso trabaja con la tabla OINM, en ella se guardan todas las transacciones que se realizan con artículos.

Es una tabla muy consultada, revisa algunos de los temas ya creados para darte un “norte”:

http://foros.consultoria-sap.com/search?q=OINM

Por ejemplo se me ocurre para ver todos los artículos que no se han “movido el día de hoy”:

SELECT * FROM OITM T0 Where T0.ItemCode Not IN (Select TX.ItemCode FROM OINM TX Where TX.DocDate = '20170807')

Ya busqué lo que había por aquí. En mi empresa había una consulta expresamente para revisar artículos con baja rotación (Gestion inactivos) pero nos da error constantemente de un tiempo a esta parte. He consultado con nuestro partner y parece que puede ser algún artículo el que esté dando problemas, pero no lo encontramos, así que creí que buscarles otra consulta podría ser de utilidad a mis compañeros, ya que en Julio hacen una revisión de esos artículos para la primera mitad del año y ya van con un mes de retraso.

En otro foro (perdón por la infidelidad) he encontrado una consulta:

-- Informe para SBO de Indicadores de Inventario

declare @dataInicio datetime
declare @dataFinal datetime
declare @tempo int

SET @tempo=(SELECT TOP 1 T0.TRANSNUM FROM OINM T0 WHERE T0.[DocDate] >=[%0] AND T0.[DocDate] <=[%1])
SET @dataInicio=(SELECT '[%0]')
SET @dataFinal=(SELECT '[%1]')

SELECT
[Artículo]=t1.itemcode,
Consumo=isnull(t1.consumo,0),
[Consumo medio diario]=isnull(t1.consumo/datediff(day,@dataInicio,@dataFinal),0),
[Stock inicial]=isnull(coalesce(t0.saldoinic,0),0),
[Stock final]=isnull(coalesce(t0.saldoinic,0)+coalesce(t1.saldofin,0),0),
[Stock promedio]= isnull((coalesce(t0.saldoinic,0)+(coalesce(t0.saldoinic,0)+t1.saldofin))/2,0),
[Rotación stock]= case isnull((coalesce(t0.saldoinic,0)+(coalesce(t0.saldoinic,0)+t1.saldofin))/2,0) when 0 then 0 else isnull(t1.consumo / ((coalesce(t0.saldoinic,0)+(coalesce(t0.saldoinic,0)+t1.saldofin))/2) ,0) end,
[Cobertura de stock]= case isnull(coalesce(t1.consumo/datediff(day,@dataInicio,@dataFinal),0),0) when 0 then 0 else isnull(((coalesce(t0.saldoinic,0)+(coalesce(t0.saldoinic,0)+t1.saldofin))/2)/ ( t1.consumo/datediff(day,@dataInicio,@dataFinal)),0) end
FROM (
SELECT
a1.itemcode,
saldoInic=isnull(sum(coalesce(s1.Inqty,0))-sum(coalesce(s1.outqty,0)),0)
FROM OITM a1
JOIN OINM s1 on a1.itemcode=s1.itemcode 
WHERE s1.docdate<@dataInicio
GROUP BY a1.itemcode
) as t0
RIGHT JOIN (
SELECT
a.itemcode,
entradas=isnull(sum(s.Inqty),0),
consumo=isnull(sum(s.outqty),0),
saldoFin=isnull(sum(s.Inqty)-sum(s.outqty),0)
FROM OINM s 
JOIN OITM a on a.itemcode=s.itemcode
WHERE s.docdate BETWEEN @dataInicio and @dataFinal
GROUP BY a.itemcode ) t1 on t1.itemcode=t0.itemcode

donde:

  • Consumo (D):El consumo de unidades en un periodo de tiempo
  • Stock promedio (Sm):Se determina calculando la media de 2 valores de stock entre dos fechas conocidas Sm=(Sinicial+Sfinal)/2
  • Rotación del stock (Rs): Frecuencia media de renovación de las existencias consideradas, durante un tiempo dado. Calculado como Rs=D/Sm Por ejemplo una rotación anual de 12 significa que las existencias consideradas se renuevan 12 veces al año, es decir una vez por mes.
  • Consumo medio diario (Cj): Calculado como el consumo D divido por el número de días del periodo de cálculo
  • Cobertura del stock (Cs): La cobertura es el stock promedio Sm dividido por el consumo medio diario Cj. El valor obtenido es el número de días de cobertura.

El listado nos muestra la siguiente información:

El código del artículo.
El consumo (D) en el periodo indicado al inicio.
El consumo diario de cada artículo (Cj), según la media entre el consumo y los días del intervalo informado.
El stock inicial (Sinicial), o stock al principio del periodo de tiempo informado.
El stock final (Sfinal) o stock en el momento de la fecha final del ámbito estudiado.
El stock promedio (Sm) en el periodo estudiado.
La rotación de stock (Rs), o las veces que se ha repuesto durante el periodo estudiado
La cobertura de stock (Cs), o los días que disponemos de stock de este articulo.

(fuente: ht_p://sapb1hub.blogspot.com.es/2010/08/calculo-de-la-rotacion-del-inventario-y.html)

Creo que podría ser un punto de partida y aunque no tiene la misma estructura que la que teníamos anteriormente, quizás les valga para salir del paso en esta ocasión.

Qué les parece a ustedes?

Cierto. Pasé sin leer esta frase. Gracias

A mi me parece muy bueno, sin embargo no te mostraría los artículos que no han tenido movimiento en el periodo que elijas, te mostraría solo aquellos que tengan por lo menos un movimiento, tal vez agregando la consulta que te comente pudiera complementarse un poco más:

declare @dataInicio datetime
declare @dataFinal datetime
declare @tempo int

SET @tempo=(SELECT TOP 1 T0.TRANSNUM FROM OINM T0 WHERE T0.[DocDate] >=[%0] AND T0.[DocDate] <=[%1])
SET @dataInicio=(SELECT '[%0]')
SET @dataFinal=(SELECT '[%1]')

SELECT
[Artículo]=t1.itemcode,
Consumo=isnull(t1.consumo,0),
[Consumo medio diario]=isnull(t1.consumo/datediff(day,@dataInicio,@dataFinal),0),
[Stock inicial]=isnull(coalesce(t0.saldoinic,0),0),
[Stock final]=isnull(coalesce(t0.saldoinic,0)+coalesce(t1.saldofin,0),0),
[Stock promedio]= isnull((coalesce(t0.saldoinic,0)+(coalesce(t0.saldoinic,0)+t1.saldofin))/2,0),
[Rotación stock]= case isnull((coalesce(t0.saldoinic,0)+(coalesce(t0.saldoinic,0)+t1.saldofin))/2,0) when 0 then 0 else isnull(t1.consumo / ((coalesce(t0.saldoinic,0)+(coalesce(t0.saldoinic,0)+t1.saldofin))/2) ,0) end,
[Cobertura de stock]= case isnull(coalesce(t1.consumo/datediff(day,@dataInicio,@dataFinal),0),0) when 0 then 0 else isnull(((coalesce(t0.saldoinic,0)+(coalesce(t0.saldoinic,0)+t1.saldofin))/2)/ ( t1.consumo/datediff(day,@dataInicio,@dataFinal)),0) end
FROM (
SELECT
a1.itemcode,
saldoInic=isnull(sum(coalesce(s1.Inqty,0))-sum(coalesce(s1.outqty,0)),0)
FROM OITM a1
JOIN OINM s1 on a1.itemcode=s1.itemcode 
WHERE s1.docdate<@dataInicio
GROUP BY a1.itemcode
) as t0
RIGHT JOIN (
SELECT
a.itemcode,
entradas=isnull(sum(s.Inqty),0),
consumo=isnull(sum(s.outqty),0),
saldoFin=isnull(sum(s.Inqty)-sum(s.outqty),0)
FROM OINM s 
JOIN OITM a on a.itemcode=s.itemcode
WHERE s.docdate BETWEEN @dataInicio and @dataFinal
GROUP BY a.itemcode ) t1 on t1.itemcode=t0.itemcode

Union All

Select 
T0.Itemcode + '  -  Inactivo en el periodo',
0,
0,
0,
0,
0,
0,
0
FROM OITM T0 
Where T0.ItemCode Not IN (Select TX.ItemCode FROM OINM TX Where TX.DocDate BETWEEN @dataInicio and @dataFinal)
1 me gusta

Fantástico con lo de “Inactivo para el período” porque así salen no sólo los que han tenido algún tipo de movimiento, si no también los que no han tenido ninguno, y muy bien identificados. Ahora bien, como en la tabla OINM aparece el campo WareHouse, cómo lo incluyo en la consulta para que me salga el almacén en el que se encuentran?
Gracias por anticipado.

La verdad no lo analice del todo, por favor verifica que te arroje los resultados correctos, en este momento carezco de tiempo así que espero puedan revisar que los resultados sean correctos.

declare @dataInicio datetime
declare @dataFinal datetime
declare @tempo int

--SET @tempo=(SELECT TOP 1 T0.TRANSNUM FROM OINM T0 WHERE T0.[DocDate] >=[%0] AND T0.[DocDate] <=[%1])
SET @dataInicio='20160101'
SET @dataFinal='20170814'

SELECT
[Artículo]=t1.itemcode,
[Almacen]=t1.Warehouse,
Consumo=isnull(t1.consumo,0),
[Consumo medio diario]=isnull(t1.consumo/datediff(day,@dataInicio,@dataFinal),0),
[Stock inicial]=isnull(coalesce(t0.saldoinic,0),0),
[Stock final]=isnull(coalesce(t0.saldoinic,0)+coalesce(t1.saldofin,0),0),
[Stock promedio]= isnull((coalesce(t0.saldoinic,0)+(coalesce(t0.saldoinic,0)+t1.saldofin))/2,0),
[Rotación stock]= case isnull((coalesce(t0.saldoinic,0)+(coalesce(t0.saldoinic,0)+t1.saldofin))/2,0) when 0 then 0 else isnull(t1.consumo / ((coalesce(t0.saldoinic,0)+(coalesce(t0.saldoinic,0)+t1.saldofin))/2) ,0) end,
[Cobertura de stock]= case isnull(coalesce(t1.consumo/datediff(day,@dataInicio,@dataFinal),0),0) when 0 then 0 else isnull(((coalesce(t0.saldoinic,0)+(coalesce(t0.saldoinic,0)+t1.saldofin))/2)/ ( t1.consumo/datediff(day,@dataInicio,@dataFinal)),0) end

FROM (SELECT a1.itemcode, saldoInic=isnull(sum(coalesce(s1.Inqty,0))-sum(coalesce(s1.outqty,0)),0) FROM OITM a1 JOIN OINM s1 on a1.itemcode=s1.itemcode 
WHERE s1.docdate<@dataInicio GROUP BY a1.itemcode) as t0
RIGHT JOIN (
SELECT
a.itemcode,
s.warehouse,
entradas=isnull(sum(s.Inqty),0),
consumo=isnull(sum(s.outqty),0),
saldoFin=isnull(sum(s.Inqty)-sum(s.outqty),0)
FROM OINM s 
JOIN OITM a on a.itemcode=s.itemcode
WHERE s.docdate BETWEEN @dataInicio and @dataFinal
GROUP BY a.itemcode, s.Warehouse) t1 on t1.itemcode=t0.itemcode

Union All

Select 
T0.Itemcode + '  -  Inactivo en el periodo',
'',
0,
0,
0,
0,
0,
0,
0
FROM OITM T0 
Where T0.ItemCode Not IN (Select TX.ItemCode FROM OINM TX Where TX.DocDate BETWEEN @dataInicio and @dataFinal)

Saludos.

1 me gusta

FANTASTICO!. Mil gracias @Gera_Mendez !!!
Ya sólo falta que a mis usuarios les guste tanto como a mí.

2 Me gusta

Este tema se cerró automáticamente 7 días después del último post. No se permiten nuevas respuestas.