Mostrando entradas con la etiqueta LEFT JOIN. Mostrar todas las entradas
Mostrando entradas con la etiqueta LEFT JOIN. Mostrar todas las entradas

miércoles, 19 de diciembre de 2012

Resolución ejercicio final (30) - Listar ventas de artículos entre fechas a un cliente determinado a partir de su DNI/CIF.





RESOLUCIÓN DEL PUNTO 28 DEL ENUNCIADO DEL EJERCICIO FINAL.

En esta entrada resolveremos el punto 28:
Listar ventas de artículos entre fechas a un cliente determinado a partir de su DNI/CIF.

Se trata de generar un listado con las cantidades de artículos vendidos entre dos fechas.

Es una consulta a dos o tres tablas dependiendo de si se desea obtener el id del artículo (3 tablas) o también su descripción (4 tablas).


Se filtrarán mediante la cláusula WHERE las líneas de factura que no cumplan con las fechas, luego estos datos serán agrupados mediante el id del artículo, a este filtro se le añadirá mediante una Y lógica (AND) la condición de que cumpla un nif determinado.

select lin_fv.id_articulo, articulos.nombre, sum(lin_fv.cantidad) as total
from lin_fv inner join cab_fv
on lin_fv.id_fv = cab_fv.id_fv
left join articulos
on lin_fv.id_articulo = articulos.id_articulo
left join clientes
on cab_fv.id_cliente = clientes.id_cliente
where cab_fv.fecha between "2012-11-01" and "2012-12-01" and
clientes.nif = "11111111A"
group by id_articulo
order by total desc;



NOTA: Se ordena el resultado de forma descendiente, mediante ORDER BY TOTAL DESC, para tener de primero el artículo más vendido.

Resolución ejercicio final (29) - Listar ventas de artículos entre fechas a un cliente determinado a partir de su id.




RESOLUCIÓN DEL PUNTO 27 DEL ENUNCIADO DEL EJERCICIO FINAL.

En esta entrada resolveremos el punto 27:
Listar ventas de artículos entre fechas a un cliente determinado a partir de su id.


Se trata de generar un listado con las cantidades de artículos vendidos entre dos fechas.

Es una consulta a dos o tres tablas dependiendo de si se desea obtener el id del artículo (2 tablas) o también su descripción (3 tablas).


Se filtrarán mediante la cláusula WHERE las líneas de factura que no cumplan con las fechas, luego estos datos serán agrupados mediante el id del artículo, a este filtro se le añadirá mediante una Y lógica (AND) la condición para que salgan datos solo de un cliente por id.

select lin_fv.id_articulo, articulos.nombre, sum(lin_fv.cantidad) as total
from lin_fv inner join cab_fv
on lin_fv.id_fv = cab_fv.id_fv
left join articulos
on lin_fv.id_articulo = articulos.id_articulo
where cab_fv.fecha between "2012-11-01" and "2012-12-01" and
cab_fv.id_cliente = 1
group by id_articulo
order by total desc;


NOTA: Se ordena el resultado de forma descendiente, mediante ORDER BY TOTAL DESC, para tener de primero el artículo más vendido.

martes, 18 de diciembre de 2012

Resolución ejercicio final (25) - Generar modelo 347



RESOLUCIÓN DEL PUNTO 22 DEL ENUNCIADO DEL EJERCICIO FINAL.

En esta entrada resolveremos el punto 22:
Generar listado de Clientes y Proveedores para generar el modelo 347 (3005,06 €).


Se trata de generar un listado en el que se incluyan los clientes y proveedores que sobrepasen la cantidad facturada (IVA incluido) de 3005,06 € (lo que se corresponde, exactamente, con las antiguas 500000 pts).


Se realizará una consulta a siete tablas (Ivas, Articulos, lineas y cabeceras tanto de facturas de venta como de albaranes de compra, clientes y proveedores )




Dada la complejidad del listado, se puede facilitar el proceso dividiéndolo en dos partes. Por una parte se buscarán los datos necesarios para los clientes y en otra para los proveedores, que luego se unirán en un único listado mediante UNION.

Para obtener los clientes, la consulta se hará a cuatro tablas.



Se podrá aprovechar la solución del punto 13 (Ver totales de cliente entre fechas)

Para poder diferenciar entre clientes y proveedores se añadirá un campo literal, que permitirá diferenciar entre unos y otros una vez unidas las consultas.

select clientes.id_cliente as id, nombre, nif,
round(sum(neto * cantidad * ((100.0 + tipo_iva) / 100.0)),2) as total, 
"cliente" as tipo
from clientes left join cab_fv
on clientes.id_cliente = cab_fv.id_cliente
left join lin_fv
on cab_fv.id_fv = lin_fv.id_fv
inner join ivas
on lin_fv.iva = ivas.codigo_iva
where cab_fv.fecha between "2012-01-01" and "2012-12-31"
group by clientes.id_cliente;


Para obtener los proveedores, la consulta es similar a la anterior solo que cambiando los campos por los correspondientes a las tablas de proveedores y albaranes de compra.


select proveedores.id_proveedor as id, nombre, nif,
round(sum(neto * cantidad * ((100.0 + tipo_iva) / 100.0)),2) as total, 
"proveedor" as tipo
from proveedores left join cab_ac
on proveedores.id_proveedor = cab_ac.id_proveedor
left join lin_ac
on cab_ac.id_ac = lin_ac.id_ac
inner join ivas
on lin_ac.iva = ivas.codigo_iva
where cab_ac.fecha between "2012-01-01" and "2012-12-31"
group by proveedores.id_proveedor;




Una vez que se tienen las dos consultas solo es preciso unirlas mediante la cláusula UNION.


select clientes.id_cliente as id, nombre, nif,
round(sum(neto * cantidad * ((100.0 + tipo_iva) / 100.0)),2) as total, 
"cliente" as tipo
from clientes left join cab_fv
on clientes.id_cliente = cab_fv.id_cliente
left join lin_fv
on cab_fv.id_fv = lin_fv.id_fv
inner join ivas
on lin_fv.iva = ivas.codigo_iva
where cab_fv.fecha between "2012-01-01" and "2012-12-31"
group by clientes.id_cliente

UNION

select proveedores.id_proveedor as id, nombre, nif,
round(sum(neto * cantidad * ((100.0 + tipo_iva) / 100.0)),2) as total, 
"proveedor" as tipo
from proveedores left join cab_ac
on proveedores.id_proveedor = cab_ac.id_proveedor
left join lin_ac
on cab_ac.id_ac = lin_ac.id_ac
inner join ivas
on lin_ac.iva = ivas.codigo_iva
where cab_ac.fecha between "2012-01-01" and "2012-12-31"
group by proveedores.id_proveedor;



El resultado es una consulta de 23 líneas.


NOTA: Una posible solución para simplificar esta consulta y facilitar su reutilización es crear una vista, mediante CREATE VIEW, para obtener los clientes, otra para los proveedores y finalmente unir ambas en una sola consulta.

Creación de la vista de clientes:

create view clientes347
(id, nombre, nif, total, tipo)
as
select clientes.id_cliente, nombre, nif,
round(sum(neto * cantidad * ((100.0 + tipo_iva) / 100.0)),2), 
"cliente"
from clientes left join cab_fv
on clientes.id_cliente = cab_fv.id_cliente
left join lin_fv
on cab_fv.id_fv = lin_fv.id_fv
inner join ivas
on lin_fv.iva = ivas.codigo_iva
where cab_fv.fecha between "2012-01-01" and "2012-12-31"
group by clientes.id_cliente;

Si se realiza un select de esta vista se obtiene como resultado el mismo que ejecutando la consulta completa:

select * from clientes347;


Creación de la vista de proveedores:

create view proveedores347
(id, nombre, nif, total, tipo)
as
select proveedores.id_proveedor, nombre, nif,
round(sum(neto * cantidad * ((100.0 + tipo_iva) / 100.0)),2), 
"proveedor"
from proveedores left join cab_ac
on proveedores.id_proveedor = cab_ac.id_proveedor
left join lin_ac
on cab_ac.id_ac = lin_ac.id_ac
inner join ivas
on lin_ac.iva = ivas.codigo_iva
where cab_ac.fecha between "2012-01-01" and "2012-12-31"
group by proveedores.id_proveedor;

Si se realiza un select de esta vista se obtiene como resultado el mismo que ejecutando la consulta completa:

select * from proveedores347;



Y finalmente para obtener el listado completo, solo será preciso realizar la unión entre ambas vistas. Recordemos que SQL trata a las vistas como si fuesen tablas.

select * from clientes347
UNION
select * from proveedores347;


jueves, 13 de diciembre de 2012

Resolución ejercicio final (18) - Ver stock de todos los productos.



RESOLUCIÓN DEL PUNTO 15 DEL ENUNCIADO DEL EJERCICIO FINAL.

En esta entrada resolveremos el punto 15:
Ver stock de todos los productos.


El proceso es idéntico al llevado a cabo para resolver el punto 14 Ver stock de un producto solo que en este caso no es preciso filtrar ningún código de artículo.

select articulos.id_articulo, nombre,
sum(lin_ac.cantidad) as compras,
sum(lin_fv.cantidad) as ventas,
(case when sum(lin_ac.cantidad) is null then 0 else sum(lin_ac.cantidad) end -
case when sum(lin_fv.cantidad) is null then 0 else sum(lin_fv.cantidad) end) as stock
from articulos left join lin_ac
on articulos.id_articulo = lin_ac.id_articulo
left join lin_fv
on articulos.id_articulo = lin_fv.id_articulo
group by id_articulo
having stock > 0;





NOTA: Se ha añadido la subcláusula HAVING para que solo salgan en el listado los artículos con stock, si se elimina esa subconsulta, se mostrarán todos los artículos, aunque no tengan stock.

Recordar que HAVING actúa como WHERE pero sobre los datos ya agrupados.






Otra posible solución es utilizar la tabla ubicación, en la cual actualizaremos el stock para cada compra y cada venta realizada.



select nombre, sum(stock) as total_stock
from articulos inner join ubicacion
on articulos.id_articulo = ubicacion.id_articulo
group by ubicacion.id_articulo
having total_stock > 0;



Resolución ejercicio final (17) - Ver stock de un producto.




RESOLUCIÓN DEL PUNTO 14 DEL ENUNCIADO DEL EJERCICIO FINAL.

En esta entrada resolveremos el punto 14:
Ver stock de un producto.


Para obtener el stock de un producto, según hemos organizado la Base de Datos, será preciso sumar todas las compras y restar todas las ventas.

Para ello se realizará un join a tres tablas.



select articulos.id_articulo, nombre,
 sum(lin_ac.cantidad) as compras, sum(lin_fv.cantidad) as ventas
 , (sum(lin_ac.cantidad) -  sum(lin_fv.cantidad)) as stock
 from articulos left join lin_ac
 on articulos.id_articulo = lin_ac.id_articulo
 left join lin_fv
 on articulos.id_articulo = lin_fv.id_articulo
 where articulos.id_articulo = 8
 group by id_articulo;


El resultado es:




En el caso de que el artículo no exista el resultado es un Empty Set:

Como ejemplo se muestra el resultado de la consulta de stock del artículo 12345, del cual no hay ni compras ni ventas. Lo cual se puede considerar correcto.



Sin embargo si el artículo existe, en la columna que no se encuentran datos, el resultado será NULL y, como es sabido las operaciones con valores NULL dan como resultado NULL.


Como ejemplo se muestra el resultado de la consulta de stock del artículo 323, del cual  hay compras pero no ventas.



NOTA: Si el artículo existe pero no tiene ni compras ni ventas los tres valores serán NULL.



Para evitar este problema, será preciso usar la expresión condicional CASE que forma parte del estándar SQL92.

Como solución se plantea la posibilidad de modificar el cálculo de la columna stock, mediante dos instrucciones CASE que transformen el valor NULL en un valor numérico cero.


select articulos.id_articulo, nombre,
sum(lin_ac.cantidad) as compras,
sum(lin_fv.cantidad) as ventas,
(case when sum(lin_ac.cantidad) is null then 0 else sum(lin_ac.cantidad) end -
case when sum(lin_fv.cantidad) is null then 0 else sum(lin_fv.cantidad) end) as stock
from articulos left join lin_ac
on articulos.id_articulo = lin_ac.id_articulo
left join lin_fv
on articulos.id_articulo = lin_fv.id_articulo
where articulos.id_articulo = 323
group by id_articulo;


En este caso a pesar de que el valor de la suma de las ventas es NULL, como se transforma en un cero mediante la sentencia CASE el cálculo del stock funciona correctamente.






Otra posible solución es utilizar la tabla ubicación, en la cual actualizaremos el stock para cada compra y cada venta realizada.



select nombre, sum(stock) as total_stock
from articulos inner join ubicacion
on articulos.id_articulo = ubicacion.id_articulo
where ubicacion.id_articulo = 8
group by ubicacion.id_articulo
having total_stock > 0;


martes, 11 de diciembre de 2012

Resolución ejercicio final (16) - Ver totales de cliente entre fechas.



RESOLUCIÓN DEL PUNTO 13 DEL ENUNCIADO DEL EJERCICIO FINAL.

En esta entrada resolveremos el punto 13:
Ver totales de cliente entre fechas.

Lo que se desea realmente es obtener la suma de todas las facturas de cada cliente, como en el punto anterior, pero añadiendo un filtrado entre fechas.

Para obtener el total en el listado es preciso realizar una consulta en la que además se sumen todas las líneas de cada factura agrupándola por cliente, tras haber sido filtradas por fechas.

Para ello se realizará un join a cuatro tablas.



Pero antes es preciso multiplicar el precio neto de cada artículo, por la cantidad de unidades, y por aplicarle el IVA correspondiente.

select clientes.id_cliente, nombre, nif,
round(sum(neto * cantidad * ((100.0 + tipo_iva) / 100.0)),2) as total
from clientes left join cab_fv
on clientes.id_cliente = cab_fv.id_cliente
left join lin_fv
on cab_fv.id_fv = lin_fv.id_fv
inner join ivas
on lin_fv.iva = ivas.codigo_iva
where cab_fv.fecha between "2012-11-22" and "2012-11-22"
group by clientes.id_cliente;



Para poder filtrar las facturas por fechas antes de proceder a la agrupación se ha añadido la penúltima línea:


En esta línea se añade una sentencia WHERE que filtra fechas mediante el operador BETWEEN, en este caso concreto para obtener las facturas de día 22 de Diciembre de 2012.

En caso de desear el listado de facturas entre dos fechas distintas, es suficiente con modificarlas.

where cab_fv.fecha between "2012-11-22" and "2012-11-22"

Como se había explicado, la sentencia WHERE filtra líneas, no grupos, por lo tanto aparecerán todos los grupos, pero estos se realizarán sólo sobre las líneas que permita WHERE. 

NOTA: Si al modificar la fechas del operador BETWEEN se indica la primera fecha superior a la segunda, se obtendrá como resultado un empty Set.

Obsérvese la diferencia al intentar obtener las facturas del mes de Noviembre.

En primer lugar filtraremos del primer día al último.

where cab_fv.fecha between "2012-11-01" and "2012-11-30"

El resultado es:



En segundo lugar filtraremos del último día al primero.

where cab_fv.fecha between "2012-11-30" and "2012-11-01"

El resultado es, en contra de lo esperado, un EMPTY SET: