Consulta con SQL (Listar fechas)

Publicado en 'Programación' por BrunoPower, 14 Mar 2013.





  1. BrunoPower

    BrunoPower Miembro nuevo

    Registro:
    14 Mar 2013
    Mensajes:
    4
    Likes:
    1




    Hola, quisiera una ayuda con una consulta que quiero hacer para un proyecto en ASP .Net con base de datos en SQL Server.

    Tengo mi tabla:

    Mi consulta recibirá 2 parámetros (Fecha inicial, fecha final) y debe mostrarme cada día desde la fecha inicial hasta la final y mostrarme el total del Monto de cada día... mi problema es que, no todos los días tienen reserva (por lo tanto no tienen monto), pero igual quiero mostrarlos pero con un total de monto igual a cero, es decir, mostrar algo así:

    Fecha_Inicial = 01/03/2013
    Fecha_Final = 05/03/2013

    HTML:
    Fecha                Monto_Total_Por_Dia
    -----------         --------------------
    01/03/2013         150
    02/03/2013         0
    03/03/2013         0
    04/03/2013         90
    05/03/2013         110
    
    Mi problema es que no sé cómo mostrar listar los días del rango de fecha, y su monto correspondiente.
    Gracias de antemano.
     


  2. tenguman

    tenguman Miembro de plata

    Registro:
    15 Nov 2010
    Mensajes:
    3,142
    Likes:
    1,016
    select Fecha_Reserva,
    sum(Monto) as monto_total_por_dia
    from reserva
    where Fecha_Reserva between '01-03-2013 00:00:00' and '05-03-2013 00:00:00'
    group by Fecha_Reserva
    order by 1 asc

    depende de que tipo de dato es tu fecha, es date, datetime o timestamp??
     
  3. Fumador

    Fumador Miembro frecuente

    Registro:
    22 Jun 2009
    Mensajes:
    162
    Likes:
    10
    Creo que hay que tener cuidado en caso que Monto sea NULL en ese caso usar: sum(isnull(Monto,0))
     
    A tenguman le gustó este mensaje.
  4. omgdinosaur

    omgdinosaur Miembro maestro

    Registro:
    9 Jun 2011
    Mensajes:
    659
    Likes:
    112
    no se podria monto inicializar en 0?
     
  5. eduar2083

    eduar2083 Miembro frecuente

    Registro:
    26 Jul 2011
    Mensajes:
    224
    Likes:
    46
    Hola. Creo que ya te dieron gran parte de la respuesta. Para un proceso de negocio por lo general Monto sería un campo obligatorio (NOT NULL) así que la Base de Datos nunca debería recibir un nulo para dicho campo y esto tendría que ser controlado desde .Net.
    Podrías armarlo como procedimiento almacenado para invocarlo desde .Net
    Código:
    CREATE PROCEDURE LIST_REPORTE
      @FEC_INICIO    DATE,
      @FEC_FIN      DATE
    AS
      SELECT
        FEC_RESERVA,
        SUM(MONTO) AS TOTAL
      FROM RESERVA
      WHERE FEC_RESERVA BETWEEN @FEC_INICIO AND @FEC_FIN
      GROUP BY FEC_RESERVA
      ORDER BY FEC_RESERVA
    GO
    
    Ahora bien, con esto podrías obtener una lista pero SOLO de los días que hubo Reservas. Para obtener aquellos días en que no hubo personalmente optaría manejarlo desde .Net.
    Una posible solución sería la siguiente:
    Código:
    Considerando que en tu capa de Entidades tienes una clase RESERVA_EN con atributos FEC_RESERVA (Fecha de reserva) y MONTO
    ...
    List<RSRVA_EN> listaReporte = InvocaProcedure();
    List<RESERVA_EN> listaCadaDia = new List<RESERVA_EN>();
    
    TimeSpan ts = fechafin - fechaInicio;
    int diferencia = ts.Days;
    
    for (int i = 0; i <= diferencia; ++i)
    {
    	RESERVA_EN entidad = new RESERVA_EN();
    
    	DateTime fecha = fechaInicio.AddDays(i);
    	entidad.FEC_RESERVA = fecha;
    	entidad.MONTO = GetMonto(fecha, listaReporte);
    	listaCadaDia.Add(entidad);
    }
    
    grilla.DataSource = listaCadaDia;
    grilla.DataBind();
    
    private decimal GetMonto(DateTime f, List<RSRVA_EN> listaReporte)
    { 
    	int i;
    	for (i = 0; i < listaReporte.Count && f != listaReporte[i].FEC_RESERVA; ++i);
    
    	return i < listaReporte.Count ? listaReporte[i].MONTO : 0;
    }
    
    Lo que hace es recorrer cada día desde Fecha Inicio hasta la fecha de Fin e ir creando una entidad, de tal forma que si la fecha se encuentra en lista que nos ha devuelto la BD, se obtendrá el monto de lo contrario le asigna cero.

    En realidad, tu problema me pareció interesante y lo implementé en C# ya que contaba con algo de tiempo :) La lista resultado (listaCadaDia) podrías volcarla hacia tu control de salida, no necesariamente un GridView. Espero haberme dejado comprender.

    Saludos.
     
  6. tenguman

    tenguman Miembro de plata

    Registro:
    15 Nov 2010
    Mensajes:
    3,142
    Likes:
    1,016
    estimado, como siempre les digo a mi gente, KISS (Keep in Simple S...), creando una funcion en C# y haciendo que se haga una busqueda de burbuja, estas utilizando procesador y memoria para crear objetos para una tarea que puede realizarse rapidamente en un motor de base de datos.

    Pongamos un ejemplo, que pasaria si fuera las reservas, digamos para una aerolinea (digamos LAN a nivel Perú nada mas), si quieres sacar un historico de esa manera, haciendo una consulta en burbuja en millones de registros, su proceso se va a demorar un monton y posiblemente haga caer el servidor o bloquee la aplicación que estas usando (y es un caso real, me paso a mi con un listado), cuando si lo realizas via SQL es un proceso muy rapido ya que las consultas estan optimizadas para eso. Cuando se programa se tiene que pensar tambien en la escalabilidad

    Dias con reserva
    Dias sin reserva
    Todos esto argumentando que no se toman por contabilizar las reservas negativas (que en algunos casos pueden existir), todo esto lo metes en un Datatable, o como se llame (lo siento, no recuerdo muy bien ASP o C# ya que los vi en el 2005) y lo muestras en un Datagrid o lo que corresponda
     
    Última edición: 17 Mar 2013
  7. eduar2083

    eduar2083 Miembro frecuente

    Registro:
    26 Jul 2011
    Mensajes:
    224
    Likes:
    46
    Hola. De acuerdo contigo tenguman. Por supuesto que una consulta SQL será mucho más rápida que hacerse desde un método sin embargo debo decirte que fue lo primero que se me ocurrió para darle una solución a BrunoPower. Por otro lado creo también que como programadores debemos tener algunas cosas claras.
    No se existe búsqueda burbuja, talvéz quisiste decir método de ordenamiento burbuja. Aún así no utilicé ningún método de ordenamiento ya que el procedure me devuelve una lista ordenada por la fecha de reserva. Si se tratase hacer un ordenamiento eficiente desde .Net tampoco se me ocurriría utilizar el Método Burbuja pues en lugar de ello optaría por un Quicksort o un OrderBy de Linq. Si se tratara de alguna búsqueda usaría un Búsqueda Binaria y no una simple secuencial como puse en mi ejemplo de arriba, claro todo esto si se tratara de lado .Net.

    Es extraño que un servidor deba caerse por una espera en la consulta, talvez sí que la aplicación web se quede bloqueada esperando la respuesta pero para eso existen teconologías como Ajax que permiten mantener una comunicación asíncrona con el servidor sin que la interacción usuario/aplicación se vea interrumpida.

    Sin embargo, de acuerdo contigo en que procesos como este caso deben manejarse desde el motor de BD.

    Saludos.
     
  8. tenguman

    tenguman Miembro de plata

    Registro:
    15 Nov 2010
    Mensajes:
    3,142
    Likes:
    1,016
    En el caso que me sucedio, la consulta demoro demasiado, consumio bastantes recursos y tiempo de espera de la pagina vencio, luego nos dimos cuenta que los hilos de consulta que se hacian consumian bastantes recursos (alrededor de 100MB por cada hilo) contando que habian 20 usuarios utilizando el sistema al mismo tiempo nos quedamos sin RAM en el server, y lo peor es que el usuario no obtenia sus datos devuelta.

    AJAX es simplemente para realizar solicitudes de request en segundo plano, pero de todas maneras se realiza la consulta, solo que sin recargar completamente la pagina, asi que igual el problema permanece, solo que en vez que no haga nada, se mostrara un iconito diciendo Loading...

    Tienes razon, no existe la busqueda en burbuja (hace muchos años que no veo ya esos temas) pero yo me referia a que realizabas una busqueda utilizando dos For anidados, con lo cual elevas el tiempo de respuesta al cuadrado (si tienes 100 registros, tu mejor tiempo sera de 200 accesos a la lista -debido a que utilizas 100 en el primer for y otros 100 en el segundo-, tu peor tiempo sera de 10 000 accesos)