¿Cómo seleccionar filas que tienen la marca de tiempo del día actual?


104

Estoy tratando de seleccionar solo los registros de hoy de una tabla de base de datos.

Actualmente uso

SELECT * FROM `table` WHERE (`timestamp` > DATE_SUB(now(), INTERVAL 1 DAY));

Pero esto toma los resultados de las últimas 24 horas, y lo necesito para seleccionar solo los resultados de hoy, ignorando el tiempo. ¿Cómo puedo seleccionar resultados basados ​​solo en la fecha?

Respuestas:


191

usar DATEyCURDATE()

SELECT * FROM `table` WHERE DATE(`timestamp`) = CURDATE()

Supongo que usar DATE todavía usa ÍNDICE .

ver el plan de ejecución en la DEMO


Vea la diferencia: SQL-Fiddle Observe el FILTRADO = 25 en la segunda consulta.
ypercubeᵀᴹ

@ypercube oh me perdí eso, pero me preguntaba por qué el valor es extra Using where; Using index.
John Woo

1
El índice se utiliza para seleccionar las filas. Pero se escanea todo el índice (y todos los valores se convierten con DATE () para evaluar la condición) con su consulta. Actualizaré mi respuesta con un mejor ejemplo.
ypercubeᵀᴹ

1
con el debido respeto, la solución ypercube es mejor por razones de rendimiento, si su tabla tiene cientos de miles de líneas, definitivamente debe ir en esta dirección
Vincent

1
los `` son importantes porque timestamp(y datecomo en mi caso) es una palabra reservada de MySQL
Victor Ferreira

55

Si desea que se use un índice y la consulta no haga un escaneo de tabla:

WHERE timestamp >= CURDATE()
  AND timestamp < CURDATE() + INTERVAL 1 DAY

Para mostrar la diferencia que esto hace en los planes de ejecución reales, probaremos con un SQL-Fiddle (un sitio extremadamente útil):

CREATE TABLE test                            --- simple table
    ( id INT NOT NULL AUTO_INCREMENT
    ,`timestamp` datetime                    --- index timestamp
    , data VARCHAR(100) NOT NULL 
          DEFAULT 'Sample data'
    , PRIMARY KEY (id)
    , INDEX t_IX (`timestamp`, id)
    ) ;

INSERT INTO test
    (`timestamp`)
VALUES
    ('2013-02-08 00:01:12'),
    ---                                      --- insert about 7k rows
    ('2013-02-08 20:01:12') ;

Probemos ahora las 2 versiones.


Versión 1 con DATE(timestamp) = ?

EXPLAIN
SELECT * FROM test 
WHERE DATE(timestamp) = CURDATE()            ---  using DATE(timestamp)
ORDER BY timestamp ;

Explique:

ID  SELECT_TYPE  TABLE  TYPE  POSSIBLE_KEYS  KEY  KEY_LEN  REF 
1   SIMPLE       test   ALL

ROWS  FILTERED  EXTRA
6671  100       Using where; Using filesort

Se filtra todos (6671) filas y luego hace una filesort (que no es un problema ya que las filas devueltas son pocos)


Versión 2 con timestamp <= ? AND timestamp < ?

EXPLAIN
SELECT * FROM test 
WHERE timestamp >= CURDATE()
  AND timestamp < CURDATE() + INTERVAL 1 DAY
ORDER BY timestamp ;

Explique:

ID  SELECT_TYPE  TABLE  TYPE  POSSIBLE_KEYS  KEY  KEY_LEN  REF 
1   SIMPLE       test   range t_IX           t_IX    9 

ROWS  FILTERED  EXTRA
2     100       Using where

Utiliza un escaneo de rango en el índice y luego lee solo las filas correspondientes de la tabla.


gran explicación y gracias por el sql-fiddle. un comentario sobre su esquema que me confundió por un momento, que INDEX t_IX (timestamp, id)podría (¿debería?) ser INDEX t_IX (timestamp), ya que la clave principal está implícita en el índice. ¿O hay alguna razón que no entiendo para hacer eso? lo probé en sql-fiddle y vi el mismo plan de ejecución (mejor)
natbro

1
@natbro Sí, si la tabla usa el motor InnoDB, el id(porque es el PK y por lo tanto el índice agrupado de la tabla) se agrega al índice de todos modos. Por lo tanto, no está de más agregarlo explícitamente (y puede detectar algunos puntos ciegos del optimizador). Ciertamente no es relevante en este caso / consulta.
ypercubeᵀᴹ

¿Alguien puede explicar por qué timestamp < CURDATE() + INTERVAL 1 DAYes necesario?
Nightwolf

@Nightwolf porque puede tener filas almacenadas donde el valor de la marca de tiempo está en el futuro. La pregunta pide "solo los registros de hoy" .
ypercubeᵀᴹ

@ TypoCubeᵀᴹ Ajá, no consideró eso simplemente porque la marca de tiempo no hará fechas futuras. No obstante, es un buen punto a tener en cuenta.
Nightwolf

11
SELECT * FROM `table` WHERE timestamp >= CURDATE()

es más corto, no es necesario usar 'AND timestamp <CURDATE () + INTERVAL 1 DAY'

porque CURDATE () siempre devuelve el día actual

Función MySQL CURDATE ()


a) La pregunta solicita "solo los registros de hoy" y su código también obtiene fechas futuras. b) Tu comparación no funciona, debes hacerlo con DATE (marca de tiempo) En otras palabras: si arreglas tu respuesta, obtendrás la respuesta original de @JohnWoo.
Katapofatico

2

¿De cuántas formas podemos despellejar a este gato? Aquí hay otra variante más.

SELECCIONAR * DESDE tableDONDE FECHA (FROM_UNIXTIME ( timestamp)) = '2015-11-18';


2

Si desea comparar con una fecha en particular, puede escribirlo directamente como:

select * from `table_name` where timestamp >= '2018-07-07';

// aquí la marca de tiempo es el nombre de la columna que tiene el tipo como marca de tiempo

o

Para obtener la fecha de hoy, la función CURDATE () está disponible, por lo que:

select * from `table_name` where timestamp >=  CURDATE();

1

Simplemente envíelo a una fecha:

SELECT * FROM `table` WHERE CAST(`timestamp` TO DATE) == CAST(NOW() TO DATE)

1

Este podría ser el más fácil en mi opinión:

SELECT * FROM `table` WHERE `timestamp` like concat(CURDATE(),'%');


0

En Visual Studio 2017, al usar la base de datos incorporada para el desarrollo, tuve problemas con la solución actual dada, tuve que cambiar el código para que funcionara porque arrojó el error de que DATE () no era una función incorporada.

Aquí está mi solución:

where CAST(TimeCalled AS DATE) = CAST(GETDATE() AS DATE)


Probablemente no estaba usando MySQL sino algún otro DBMS (¿SQL Server quizás?) Observe las etiquetas de la pregunta.
ypercubeᵀᴹ
Al usar nuestro sitio, usted reconoce que ha leído y comprende nuestra Política de Cookies y Política de Privacidad.
Licensed under cc by-sa 3.0 with attribution required.