Consulta SQL complicada

Tengo que realizar una consulta, pero a pesar de razonarla un tiempo no logro hacerla.
Dispongo de:
Tabla de productos:
IdProducto
Nombre
Tabla ventas:
Dia (dia,mes,año)
IdProducto
Cantidad
En un día puedo registrar las ventas de distintos productos.
La idea es realizar una consulta, cuyo resultado sea:
FECHA. NombreProducto NombreProducto
10/04/05 50 100
11/04/05 10
El tema es que las columnas no serán siempre las mismas, porque tendrá los nombres de los materiales consumidos en el periodo, o bien. Lo mismo, si un producto solo ha sido vendido una vez, aparecerá en el día correspondiente y el resto serán nullos.
No se si soy claro, pero algo así es la forma del informe que quiero.
¿Puedo realizar esto con una sola consulta SQL?
Si bien, desde programación, puedo lograr ese resultado efectuando varias consultas, mi idea es en una sola tener todo el conjunto de datos deseados.

1 respuesta

Respuesta
1
Bien, me has hecho pensar un poco, hace algún tiempo mientras desarrollaba una aplicación hice algo parecido, pero para hacerlo tuve que implementar una función.
1° Paso: Implementa una función que sea capaz de devolverte a partir de una fecha una cadena de caracteres donde incluya el código del producto concatenado con la cantidad.
CREATE FUNCTION dbo.fn_ProductosporFecha (@Fecha as datetime)
RETURNS nvarchar (4000) AS
Begin
Declare @IdProducto as int
Declare @NombreProducto as varchar(50)
Declare @Cantidad int
Declare @Cadena as nvarchar(4000)
DECLARE ProductosporFecha CURSOR FOR
SELECT TOP 100 PERCENT dbo.tVentas.IdProducto
FROM dbo.tVentas INNER JOIN dbo.tProductos ON dbo.tVentas.IdProducto = dbo.tProductos.IdProducto
WHERE Year(dbo.tVentas.FechaVenta)=Year(@Fecha) and Month(dbo.tVentas.FechaVenta) = Month(@Fecha) and Day(dbo.tVentas.FechaVenta) = Day(@Fecha)
OPEN ProductosporFecha
FETCH NEXT FROM ProductosporFecha INTO @IdProducto
WHILE @@FETCH_STATUS = 0
BEGIN
Set @Cantidad = (Select top 1 Cantidad From dbo.tVentas Where dbo.tVentas.IdProducto = @IdProducto and
Year(dbo.tVentas.FechaVenta)=Year(@Fecha) and Month(dbo.tVentas.FechaVenta) = Month(@Fecha) and Day(dbo.tVentas.FechaVenta) = Day(@Fecha))
Set @Cadena = Isnull(@Cadena,'' ) + CAST(@Cantidad as varchar(5)) + ',' + CAST(@IdProducto as varchar(5)) + '|'
FETCH NEXT FROM ProductosporFecha INTO @IdProducto
END
CLOSE ProductosporFecha
DEALLOCATE ProductosporFecha
if len(@Cadena) > 0
Set @Cadena = left(@Cadena, len(@Cadena) - 1 )
return @Cadena
END
2° Paso: Prueba que la función efectivamente te devuelva por cada fecha, la cadena de caracteres, para llamarla solo tienes que hacer esto:
select dbo.fn_ProductosporFecha('2006-06-01')
Te devolverá una cadena como esta:
5,1|1,2|6,3|10,4
3° Paso: Para finalizar solo tienes que realizar una query en donde obtengas las fechas distintas y llames a la función en la query.
Select Distinct Fechaventa, dbo.fn_ProductosporFecha(FechaVenta) as ProductosporFecha from tVentas
Lo más complejo de todo esto es el tema de la Función, dale unas vueltas, al final verás que es sencillo.
El Join lo estoy usando sin drama, y el tema de los alias que me explicaste lo tengo entendido también.
Pero fíjate esta consulta, el problema está en que el número de columnas que necesito es variable. Yo solo quiero que me devuelva un resultado, en el que cada fila contenga: fecha, y una serie de valores de cada uno de los productos que fueron vendidos para la fecha.
Por ejemplo: si yo hago
SELECT Select t2.Fecha, t1.NombreProducto, t2.Cantidad from Productos t1 JOIN Ventas t2 ON t1.idProducto=t1.i WHERE t1.Fecha=hoy;
Eso me devuelve una cantidad de filas con los nombres y cantidades de los productos vendidos en la fecha. Pero ¿si yo quiero que me devuelva una sola fila y que cada columna represente un la cantidad del producto?
Es raro lo que pido, lo se... conozco bastante de SQL, pero no se me ocurre como hacer esto y estoy buscando la manera de hacerlo.
Espero se entienda mi pregunta.
Le hice unos cambios a la función y ahora te devolverá la cantidad con el Nombre, de estas forma:
5,Cafe|1,Leche|6,Pan|10,Queso
ALTER FUNCTION dbo.fn_ProductosporFecha (@Fecha as datetime)
RETURNS nvarchar (4000) AS
BEGIN
Declare @IdProducto as int
Declare @NombreProducto as varchar(50)
Declare @Cantidad int
Declare @Cadena as nvarchar(4000)
DECLARE ProductosporFecha CURSOR FOR
SELECT TOP 100 PERCENT dbo.tVentas.IdProducto
FROM dbo.tVentas INNER JOIN dbo.tProductos ON dbo.tVentas.IdProducto = dbo.tProductos.IdProducto
WHERE Year(dbo.tVentas.FechaVenta)=Year(@Fecha) and Month(dbo.tVentas.FechaVenta) = Month(@Fecha) and Day(dbo.tVentas.FechaVenta) = Day(@Fecha)
OPEN ProductosporFecha
FETCH NEXT FROM ProductosporFecha INTO @IdProducto
WHILE @@FETCH_STATUS = 0
BEGIN
Set @Cantidad = (Select top 1 Cantidad From dbo.tVentas Where dbo.tVentas.IdProducto = @IdProducto and
Year(dbo.tVentas.FechaVenta)=Year(@Fecha) and Month(dbo.tVentas.FechaVenta) = Month(@Fecha) and Day(dbo.tVentas.FechaVenta) = Day(@Fecha))
Set @NombreProducto = (Select top 1 NombreProducto From dbo.tProductos Where dbo.tProductos.IdProducto = @IdProducto)
Set @Cadena = Isnull(@Cadena,'' ) + CAST(@Cantidad as varchar(5)) + ',' + @NombreProducto + '|'
FETCH NEXT FROM ProductosporFecha INTO @IdProducto
END
CLOSE ProductosporFecha
DEALLOCATE ProductosporFecha
if len(@Cadena) > 0
Set @Cadena = left(@Cadena, len(@Cadena) - 1 )
return @Cadena
END
Al final, la query debiera quedarte de esta forma:
2006-06-01 00:00:00.000 5,Cafe|1,Leche|6,Pan|10,Queso
2006-06-02 00:00:00.000 5,Cafe|1,Leche|6,Pan|10,Queso
Creo que eso es lo que más se acerca a lo que tenías en mente.
Tienes dos tablas Productos y Ventas. Estas dos tablas tienen un dato en común que es el IdProducto, a partir de este dato puedes realizar la consulta.
Ej. En este caso usaré un CROSS JOIN
Select t2.Fecha, t1.NombreProducto, t2.Cantidad from Productos t1 CROSS JOIN Ventas t2
-En esta query estoy usando un alias t1 para Productos y t2 Para Ventas.
Espero que te sirva, de todas maneras sería bueno que le echaras una mirada a todo lo relacionado con los JOIN.

Añade tu respuesta

Haz clic para o

Más respuestas relacionadas