Bueno, viendo lo que planteas, vamos a partir de una serie de supuestos (tú dirás si están bien)
1) Todo producto tiene una familia.
2) Todo producto tiene una línea.
3) Todo producto tiene o tuvo un stock incial (no existen productos sin stock, aunque sea cero).
4) Todo producto
pudo haber tenido un movimiento de almacén.
Si esos cuatro considerando son reales, debes usar INNER JOIN en las tres primeras condiciones y un LEFT JOIN sólo en la última, y para que sea eficiente, se debe poner el movimiento al final.
Además,
no puedes agrupar por ingreso y egreso, eso no tiene sentido, porque estás buscando sumar los ingresos y egresos
de los productos. Por lo demás, la consulta está bien.
Lo que sí debo acosnejarte es que nunca jamás pongas cadenas de caracteres en una suma, como hiciste en el IF() del SUM(). Si vas a sumar, debe ser un número, no una cadena. Si el servidor no está habilitado para conversiones implícitas te generará un error de tipo de dato o te devolvería NULL.
La idea es mas o menos así:
Código MySQL:
Ver original `p`.`id_linea`,
`p`.`id_familia`,
`p`.`id_producto`,
`p`.`UND`,
`p`.`descripcion`,
IFNULL(`stki`.
`stock`, 0) stock
, SUM(if(`ma`.
`tip_movimiento` = 'INGRESO', `ma`.
`cantidad`, 0)) `ingresos`, SUM(if(`ma`.
`tip_movimiento` = 'SALIDA', `ma`.
`cantidad`, 0)) `salidas`, `p`.`stock_minimo`,
`p`.`stock_maximo`,
`l`.`nom_linea`,
`fa`.`nom_familia`
`producto` `p`
INNER JOIN `lineas` `l` ON `l`.
`id_linea` = `p`.
`id_linea` INNER JOIN `familia` `fa` ON `fa`.
`id_linea` = `p`.
`id_linea` INNER JOIN `stock_inicial` `stki` ON `p`.
`id_producto` = `stki`.
`id_producto` LEFT JOIN `movimiento_almacen` `ma` ON `ma`.
`id_producto` = `p`.
`id_producto` GROUP BY `p`.
`id_producto`,`ma`.
`tip_movimiento` ORDER BY `p`.
`id_linea`,`p`.
`id_familia`,`p`.
`id_producto` ASC;
Un detalle más: La próxima vez que se te pida la estructura de las tablas, no uses DESCRIBE. Eso no nos permite ver las dependencias funcionales. Usa mejor SHOW CREATE TABLE:
Eso sí devolverá la sentencia de creación.