Ir al contenido principal

Consultas SQL basadas en fecha y/o hora

Manejando SQL Server 2005, me encontre que tratando hacer consultas basadas en fechas, obtenía como resultado nada (empty). Esto se debía a que no tenía claro como trabajan los tipos de dato datetime y smalldatetime. Estos dos tipos de datos son muy similares, se diferencia en que datetime es más detallado a la hora de almacenar la fecha. Estas diferencias pueden ser vistas en la siguiente tabla:




















Tipo


Minimo


Maximo


Precision


datetime


Ene 1, 1753
media-noche

Dic 31, 9999 23:59:59.997
(0.003 segundos hasta la media-noche)

Más cercano
3.33 millisegundos

smalldatetime


Ene 1, 1900
media-noche

Jun 6, 2079 23:59
(un minuto hasta la media-noche)

Más cercano al mínuto


Ambos, representan una fecha y hora que es igual al número de días en relación a una fecha base. En SQL Server la fecha base es la medianoche del 1 de Enero de 1900. Observando la tabla, el tipo de dato smalldatetime, puede solo representar fechas desde esta fecha base, en cambio el datetime puede representar fechas antes del 1 de enero de 1900. Para hacer esto, el almacena el valor como número negativo.

Para visualizar, como estos valores son guardados.
Piensa en un valor decimal, cuya parte entera representa los días desde la fecha base y la parte fraccional (los numeros después del punto) representan la hora. Por ejemplo, el valor date/time mediodía del 4 de enero de 1900, es almacenado como 3.5, donde 3, representa tres días desde la fecha base y el 0.5, representa la mitad del día. Para ver esto en el SQL Server, ejecuta la siguiente consulta:
SELECT CAST(CAST('1900-01-04 12:00' AS datetime) AS float)

Otro datito importante es saber que el SQL Server no provee un tipo de dato que solo almacene fecha u hora.  Es decir, que si tu almacenas un valor sin la hora (la parte fraccional) se le asigna el valor de cero (0). De igual forma, si tu almacenas un valor sin la fecha, la parte entera se le asigna automáticamente el valor de cero (0), que para la fecha significa 1 de enero de 1900. Para ejemplo, ejecuta la siguiente consulta:

SELECT CAST('1900-01-04' AS datetime), CAST('10:00' AS datetime)

el cual retornará el siguiente resultado:
1900-01-04 00:00:00.000         1900-01-01 10:00:00.000

Como Buscar Solo la Fecha

Para ilustrar usaremos la siguiente tabla:

ID  DateVal
--  -----------------------
1   2001-02-28 10:00:00.000
2   2002-02-28 13:58:32.823
3   2002-02-29 00:00:00.000
4   2002-02-28 00:00:00.000


 Si realizamos la siguiente consulta:
SELECT * FROM DateSample WHERE DateVal = '2002-02-28'

El resultado solo traerá la fila #4, esto se debe a que el SQL Server buscará los datos cuya hora sea 00:00:00 (medianoche). El valor literal buscado (28 de febrero de 2002) implicítamente se le agregará la hora antes en mención. Entonces, como podemos evitar este suceso y obtener todos los registros cuya fecha sea 28 de febrero de 2002? Lo haremos de la siguiente forma:

Si la consulta es ejecuta frecuentemente, tú debes basar tu búsqueda en un rango de fechas, como la siguiente:
SELECT * FROM DateSample WHERE DateVal BETWEEN '2002-02-28' AND '2002-02-28 23:59:59.997'

Nota: Ahora pensarás que yo soy un brutón porque debi usar como límite superior '2002-02-29' en vez de '2002-02-28 23:59:59.997'. Pués no, si haces esto, la fila #3 será parte del resultado de tu consulta.

Otra forma de obtener el resultado de manera más sencilla (la que yo recomiendo), es de la siguiente manera:
SELECT * FROM DateSample WHERE DateVal >= '2002-02-28' AND DateVal < '2002-02-29'

Como Buscar Solo por la Hora (How to search by time)

Para ilustrar, consideremos la siguiente tabla:

ID  TimeVal
--  -----------------------
1   2002-02-28 10:00:00.000
2   1900-01-01 13:58:32.823
3   1900-01-01 09:59:59.997
4   1900-01-01 10:00:00.000


Si usamos la siguiente consulta para extraer las filas cuya hora es igual a las 10:00 AM:
SELECT * FROM TimeSample WHERE TimeVal = '10:00:00'

solo conseguiremos la fila #4. La fila #1 no será parte del resultado, debido a que sucede lo mismo que con la fecha, pero en este caso el valor que es implicítamente agregado, es la fecha. En adición, la fila #3 no es parte del resultado porque es un valor super cerca, pero no igual a las 10:00 AM.
Para obviar la fecha, tu puedes crear una consulta que corte la parte entera del valor date/time, y solo deje la parte fraccional. Esta sería de la siguiente forma:

SELECT * FROM TimeSample WHERE TimeVal - CAST(FLOOR(CAST(TimeVal AS float)) AS datetime) = '10:00' 

Esta consulta nos devolvería la fila 1 y 4. Lamentablemente, no hay otra forma de conseguir este resultado sin usar esta combinación de formulas. Por tal motivo, hay que tomar mucho cuidado como se almacena la data datetime/smalldatetime que solo se usa para horas (time-only). Si tú necesitas realizar frecuentemente este tipo de búsqueda, te recomiendo que analices y reestructures el diseño de tu base de datos.

Si tú deseas hacer consultas basadas solo por horas para un intervalo de tiempo, bastaría con una simple consulta (query), esto; tomando en cuenta que se ha almacenado la data hora (time-only) consistentemente sin el componente fecha. La consulta sería algo como esto:

SELECT * FROM TimeSample WHERE TimeVal BETWEEN '09:59' AND '10:01'

o

SELECT * FROM TimeSample WHERE TimeVal > '09:59' AND TimeVal < '10:01' 

Estas dos consultas retornarían los datos de la fila #3 y #4.

Si los datos de hora (time-only) han sido guardados en la base de datos inconsistemente, entonces se necesitará que la consulta evite o excluya la parte fecha de estos. Por ejemplo, tu podrías usar una consulta como esta:

SELECT * FROM TimeSample WHERE TimeVal - CAST(FLOOR(CAST(TimeVal AS float)) AS datetime) > '09:59' AND TimeVal - CAST(FLOOR(CAST(TimeVal AS float)) AS datetime) < '10:01'


la cual nos devuelve las filas 1, 3 y 4. Recuerden que no podrías realizar correctamente la búsqueda sin estas funciones, cuando la data hora ha sido guardada inconsistentemente.

Nota: Toda esta información ha sido traducida del libro Murach's SQL for SQL Server del autor Bryan Syverson.

Comentarios

  1. [...] FROM tblMiTabla WHERE Fecha > '2008-05-01' AND Fecha < '2008-05-12' Paginas relacionadas: - http://rdgz.wordpress.com/2008/01/13...fecha-yo-hora/ - http://sql.manivesa.com/Tutoriales+S...nados/313.aspx Recuerda por favor marcar el post si te [...]

    ResponderEliminar
  2. wOooW!!! muchas gracias no sabes cuanto me ayudo este post con lo del date, me salvaste.

    Gracias por este gran aporte!

    ResponderEliminar
  3. Gracias por compartir tus conocimientos

    Excelente apunte

    Gracias

    ResponderEliminar
  4. hola tengo un proble que no he podido resolver, donde me preguntan la fecha separacion menor a un mes.
    "Listar todos los pacientes que hayan recibido un tratamiento de radioterapia y quimioterapia con separación menor a un mes. Además en este listado debe indicar por cada paciente las fechas en que se aplicaron estos tratamientos, además de sus nombres."

    ResponderEliminar
  5. De 20!! me salvaste gracias

    ResponderEliminar
  6. Hola.
    Muchas gracias por el artículo. Me sirvió para desatascarme.

    ResponderEliminar
  7. como resuelvo para poner un rango de horas por ejemplo
    una hora de confirmacion y una hora de salida
    y ver todas las horas que estan confirmadas 35 minutos antes que la hora de salida..................

    ResponderEliminar
  8. Gran post, muchas gracias!

    ResponderEliminar
  9. necesito hacer una busqueda por fecha o por hora
    es una consulta de paciente por hora

    ResponderEliminar
  10. quiero saber todos los paciente k me tocan por ejemplo a dicha hora

    ResponderEliminar
  11. Muchas gracias por su aportacion
    muy buena página, gracias a Dios que los encontré....

    ResponderEliminar
  12. Gracias, primera vez!!

    ResponderEliminar
  13. Muchas gracias por explicar esto!

    Me ayudo mucho además de que esta muy claro, de verdad muchas gracias.

    ResponderEliminar
  14. Gracias, la información me fue muy útil.

    ResponderEliminar
  15. Gracias Brenda!!!
    Disculpa la tardanza en responderte.
    La vida es corta para la cantidad de cosas que tenemos que hacer

    ResponderEliminar
  16. Me marca error en el signo "-"... en sql server 200...

    ResponderEliminar

Publicar un comentario

Entradas populares de este blog

Error al recuperar un generador de clases COM para el componente con CLSID {############} debido al siguiente error: 80040154

Hello Everyone!! Realmente no se si este mensaje de error es genérico o específio. Por ende, voy a decirles que si están: - Usan Visual Studio 2010 - Windows 7 x64 - Y tan trantando de correr un programa desarrollado en una versión anterior al VS 2010 y que hace referencia a DLL's, entonces chequeate este video, porque te va a dar la solución: www.youtube.com/watch?v=pDtyGns6mOw Fin!!!

Como Aplicar un Patch a un Programa en Linux (How to Apply a Patch en Linux)

Los comandos aplicados en este articulo fueron realizados en la distro Kali 1.0 (based in Debian) Una de las ventajas de los programas (software) open source es que podemos descargar los paquetes fuentes de estos que son los que contienen todos los codigos fuentes. Con ellos podriamos, modificar el mismo y crear nuevas funcionalidades (features) o corregir algun fallo. Para mantener un orden o integridad, es bueno que las modificaciones hechas al paquete fuente original, se realicen en un patch file. El patch file es un archivo que debe aplicarse al codigo fuente original utilizando el comando con el nombre patch . Que contiene un archivo patch? Contiene lineas de codigo fuente de uno o mas archivos contenidos en el paquete fuente original. La extension de un archivo patch es .patch Consideraciones Cosas que hasta el momento no encontre en la Web y que debes de saber de como aplicar un Patch son: 1.  El patch se aplica al paquete fuente de la aplicacion que deseas aplicar

Pasar Valores de Ventana Hija a Padre (Pass values from Child to Parent Windows with PHP and Javascript)

En este articulo, la ventana hija es un listado de clientes, donde el usuario a darle clic a un cliente, se retorna el ID del Cliente a un objeto Input tipo  hidden y el Nombre del Cliente a un objeto Input tipo  Text . En la ventana padre agrega un hipervinculo como el siguiente: <a href="#" id="customer_search" onClick="showModalSendAndReturnValues('customers_search.php', ''); return false;">Abrir Ventana Hija</a> y crea dos objetos HTML Input: <input type="text" id="customer_name"> <input type="hidden" id="customer_id"> El evento onClick sera el que dispare la función que abre la ventana hija.  El return false , es importante ya que evita que la ventana padre se auto-refresque y nos lleve a otra pagina. La funcion showModalSendAndReturnValues , es un Javascript que puede ir en el header de tu pagina padre o en un archivo de funciones javas