www.clarioneros.com

El rincón de los desarrolladores
Fecha actual Jue Ago 24, 2017 4:58 am

Todos los horarios son UTC




Nuevo tema Responder al tema  [ 12 mensajes ]  Ir a página 1, 2  Siguiente
Autor Mensaje
NotaPublicado: Dom Feb 20, 2011 7:24 pm 
Desconectado
Avatar de Usuario

Registrado: Dom Feb 06, 2011 9:34 am
Mensajes: 1008
Ubicación: España
Sé que no es viernes, no recuerdo tampoco cuál fue el último número de A seguir pensando y este tampoco es un problema matemático. De hecho estuve a punto de inaugurar una nueva serie, PPP (Problemas para pensar) pero me pareció que teníamos que mantener el nombre que Daniel le había puesto.
Bien, de qué se trata esta vez? Es un problema de programación con algunas características. Primero, está involucrado SQL. Supongo que cualquier tipo de SQL pero en este caso es el de Microsoft. Segundo, el problema tiene muchas soluciones, la idea es encontrar la más práctica.

He aquí el problema: tenemos una tabla en SQL llamada Facturas. Entre sus campos hay un número de factura (único), una fecha, un código de cliente y un total de la factura. Podría tener más pero a nosotros nos interesan solo estos. La idea es generar un browse o listado de lo facturado por día. Fácil, no? Pero hay una pequeña trampa, si un día no se facturó nada, ese día debe aparecer en el browse/listado con importe 0.

Ej:
Nro. Factura Fecha Cliente TotalFacturado
1 01/02/2011 23 150
2 01/02/2011 17 100
3 03/02/2011 2 86
4 04/02/2011 5 200

Ahora queremos ver lo facturado entre el 01/02/2011 y el 07/02/2011, deberíamos tener algo así:
Fecha TotalFacturado
01/02/2011 250
02/02/2011 0
03/02/2011 86
04/02/2011 200
05/02/2011 0
06/02/2011 0
07/02/2011 0

La solución más fácil es ir agregando registros si no hay para esa fecha pero si el período es muy largo eso puede ser algo tedioso.
En un libro de SQL que estoy leyendo encontré una solución más elegante (al menos eso creo yo).
Qué proponen uds.?

_________________
Mauricio, básicamente usando Clarion 6.3
www.tdcsoftware.com y www.clarioneros.com/blog


Arriba
 Perfil Email  
 
NotaPublicado: Lun Feb 21, 2011 12:56 pm 
Desconectado
Avatar de Usuario

Registrado: Dom Feb 06, 2011 7:45 pm
Mensajes: 124
Ubicación: Uruguay
No sé si será más elegante, pero voy a presentar una forma de hacerlo.

Primero vamos a mostrar cómo obtener una secuencia de fechas utilizando la recursividad. Como los datos después se los voy a agregar de la tabla Orders de la base Northtwind (que casi todos tenemos instalada) y los datos de esa tabla comienzan en julio de 1996, vamos a generar la secuencia de fechas de ese mes:

Código:
DECLARE @Fecha DATE;
SET @Fecha='1996-07-01';
WITH Fechador (Fecha) as
(
   SELECT @Fecha
   UNION ALL
   SELECT DATEADD(day,1,Fecha)
   FROM Fechador
   WHERE Fecha < '1996-07-31'
   )
   SELECT Fecha FROM Fechador
   GO


Ahora que tenemos la secuencia, le agregamos los datos de las órdenes correspondientes al mes mediante un simple JOIN y agrupando por fecha para totalizar:

Código:
DECLARE @Fecha DATE;
SET @Fecha='1996-07-01';
WITH Fechador (Fecha) AS
(
   SELECT @Fecha AS Fecha
   UNION ALL
   SELECT DATEADD(day,1,Fecha) FROM Fechador WHERE Fecha<'1996-07-31'
   )
   SELECT Fecha, SUM(Quantity*UnitPrice) AS Total FROM Fechador
   LEFT OUTER JOIN Orders ON Fecha=Orders.OrderDate
   LEFT OUTER JOIN OrderDetails ON OrderDetails.OrderID=Orders.OrderID
   GROUP BY Fecha
   GO


Con esta técnica, los días que no tienen órdenes salen con NULL (no con cero), pero es una aproximación. ¿Hay alguna otra forma?

_________________
¡Saludos!

Daniel Ruzo
www.amazingGUI.com

Yo creo en la reencarnación:
antes tenía una vida y ahora soy programador


Última edición por DanielRuzo el Mié Feb 23, 2011 1:56 pm, editado 3 veces en total

Arriba
 Perfil Email  
 
NotaPublicado: Lun Feb 21, 2011 1:01 pm 
Desconectado
Avatar de Usuario

Registrado: Dom Feb 06, 2011 9:34 am
Mensajes: 1008
Ubicación: España
Es "parecida" a la solución que tengo. No me animo a decir que la mía es mejor, tal vez la vea un poquitín más sencilla.
Vamos a ver si alguien aporta algo más y si no publico la mía que además puede utilizarse para otras cosas.

_________________
Mauricio, básicamente usando Clarion 6.3
www.tdcsoftware.com y www.clarioneros.com/blog


Arriba
 Perfil Email  
 
NotaPublicado: Lun Feb 21, 2011 1:26 pm 
Desconectado
Avatar de Usuario

Registrado: Dom Feb 06, 2011 7:45 pm
Mensajes: 124
Ubicación: Uruguay
Bueno, se podría evitar la definición de la variable utilizada para tomar la primera fecha haciéndolo con un CAST en el primer SELECT, y se podría también utilizar UNION en lugar de un JOIN para evitar que salgan los NULL. Pero esperemos tu solución.

_________________
¡Saludos!

Daniel Ruzo
www.amazingGUI.com

Yo creo en la reencarnación:
antes tenía una vida y ahora soy programador


Arriba
 Perfil Email  
 
NotaPublicado: Lun Feb 21, 2011 1:32 pm 
Desconectado
Avatar de Usuario

Registrado: Dom Feb 06, 2011 9:34 am
Mensajes: 1008
Ubicación: España
Te doy una idea. En la solución se usa una tabla auxiliar. De acuerdo al autor la tabla esa la usa en todas sus bases de datos así que la define en la base de datos Model. Lo bueno, como dije antes, es que la tabla esa tiene muchos otros usos.

_________________
Mauricio, básicamente usando Clarion 6.3
www.tdcsoftware.com y www.clarioneros.com/blog


Arriba
 Perfil Email  
 
NotaPublicado: Lun Feb 21, 2011 2:37 pm 
Desconectado
Avatar de Usuario

Registrado: Dom Feb 06, 2011 7:45 pm
Mensajes: 124
Ubicación: Uruguay
Mmmmm...será cuestión de gustos, pero si usa una tabla auxiliar ya no me parece elegante. ¿Será por lo de la stupid table?

Pero esperemos... esperemos la solución.

_________________
¡Saludos!

Daniel Ruzo
www.amazingGUI.com

Yo creo en la reencarnación:
antes tenía una vida y ahora soy programador


Arriba
 Perfil Email  
 
NotaPublicado: Mié Feb 23, 2011 12:06 am 
Desconectado
Avatar de Usuario

Registrado: Dom Feb 06, 2011 7:45 pm
Mensajes: 124
Ubicación: Uruguay
¿Y? ¿Para cuándo tu solución?

_________________
¡Saludos!

Daniel Ruzo
www.amazingGUI.com

Yo creo en la reencarnación:
antes tenía una vida y ahora soy programador


Arriba
 Perfil Email  
 
NotaPublicado: Mié Feb 23, 2011 10:30 am 
Desconectado
Avatar de Usuario

Registrado: Dom Feb 06, 2011 9:34 am
Mensajes: 1008
Ubicación: España
Quería ver si alguien más se enganchaba pero parece que no, así que no me queda otra que publicar la solución. Aclaro de nuevo que no digo que es la mejor ni mucho menos.
Como dije antes, necesita una tabla auxiliar, la llamaremos Numeros. Esta tabla tiene una secuencia de, oh casualidad, números, del 1 al que nosotros querramos, puede ser 1.000.000 por ejemplo. La podemos crear en cualquier base de datos pero si lo hacemos en Model la tenemos disponible para cualquiera de nuestra base de datos. O podemos usar CREATE SYNONYM también.

Una vez creada la tabla, el resto es bastante parecido a lo que vos hiciste.

Código:
SELECT DATEADD(day, Numeros.n - 1, '20060101') AS FechaFactura,
  SUM(F.TotalFactura)
FROM Numeros
  LEFT OUTER JOIN Facturas AS F
    ON DATEADD(day, Numeros.n - 1, '20060101') = F.FechaFactura
WHERE Numeros.n <= DATEDIFF(day, '20060101', '20081231') + 1
GROUP BY DATEADD(day, Numeros.n - 1, '20060101')
ORDER BY FechaFactura;


Lo bueno de esta tabla es que se puede utilizar para muchas otras cosas, por ejemplo para encontrar el menor número faltante en una secuencia (suponete que tenés un código de artículo numérico e ingresaron el 1,2,3,6,7,8... etc.. La idea es encontrar el 4 en forma sencilla) y cosas así.

_________________
Mauricio, básicamente usando Clarion 6.3
www.tdcsoftware.com y www.clarioneros.com/blog


Arriba
 Perfil Email  
 
NotaPublicado: Mié Feb 23, 2011 3:02 pm 
Desconectado
Avatar de Usuario

Registrado: Dom Feb 06, 2011 7:45 pm
Mensajes: 124
Ubicación: Uruguay
Acepto lo de que es más simple pero como dije me resulta más elegante lo del secuenciador. Reitero que es una cuestión de gustos, pero eso de tener una tabla que no representa nada me parece traído de los pelos (como lo de la tabla estúpida para usar de buffer en Clarion).

Si no querés repetir el secuenciador cada vez que lo usás se podría crear un Stored Procedure. Y en mi ejemplo utilicé un secuenciador de fechas pero perfectamente puede ser un secuenciador de enteros.

Gracias por el acertijo. Personalmente sé poquito de SQL y con esto me hiciste mover las neuronas.

_________________
¡Saludos!

Daniel Ruzo
www.amazingGUI.com

Yo creo en la reencarnación:
antes tenía una vida y ahora soy programador


Arriba
 Perfil Email  
 
NotaPublicado: Mié Feb 23, 2011 5:57 pm 
Desconectado
Avatar de Usuario

Registrado: Dom Feb 06, 2011 9:34 am
Mensajes: 1008
Ubicación: España
Creo que lo interesante de esto es no solo las soluciones sino que ambas son del lado del motor. Una de las cosas más importantes que debemos hacer cuando programamos con SQL, sea con el lenguaje que sea, es aprender a resolver la mayor cantidad de los problemas en el motor. De esa forma vamos a generar menos tráfico y los programas serán más eficientes.

_________________
Mauricio, básicamente usando Clarion 6.3
www.tdcsoftware.com y www.clarioneros.com/blog


Arriba
 Perfil Email  
 
Mostrar mensajes previos:  Ordenar por  
Nuevo tema Responder al tema  [ 12 mensajes ]  Ir a página 1, 2  Siguiente

Todos los horarios son UTC


¿Quién está conectado?

Usuarios navegando por este Foro: No hay usuarios registrados visitando el Foro y 1 invitado


No puede abrir nuevos temas en este Foro
No puede responder a temas en este Foro
No puede editar sus mensajes en este Foro
No puede borrar sus mensajes en este Foro
No puede enviar adjuntos en este Foro

Saltar a:  
cron
Powered by phpBB® Forum Software © phpBB Group
Traducción al español por Huan Manwë para phpbb-es.com