Como selecionar linhas que possuem o carimbo de data / hora do dia atual?


104

Estou tentando selecionar apenas os registros de hoje de uma tabela de banco de dados.

Atualmente eu uso

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

Mas isso leva os resultados das últimas 24 horas, e preciso selecionar apenas os resultados de hoje, ignorando o tempo. Como posso selecionar os resultados apenas com base na data?

Respostas:


191

usar DATEeCURDATE()

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

Eu acho que usar DATE ainda usa INDEX .

veja o plano de execução no DEMO


Veja a diferença: SQL-Fiddle Observe o FILTERED = 25 na 2ª consulta.
ypercubeᵀᴹ

@ypercube oh, eu perdi isso, mas estava me perguntando por que o valor é extra Using where; Using index?
John Woo

1
O índice é usado para selecionar as linhas. Mas todo o índice é verificado (e todos os valores são convertidos com DATE () para avaliar a condição) com sua consulta. Vou atualizar minha resposta com um exemplo melhor.
ypercubeᵀᴹ

1
com todo o respeito, a solução ypercube é melhor por motivos de desempenho, se sua mesa tiver centenas de milhares de linhas, você definitivamente deve ir nesta direção
Vincent

1
os `` são importantes porque timestamp(e datecomo no meu caso) é uma palavra reservada do MySQL
Victor Ferreira

55

Se você quiser que um índice seja usado e a consulta não faça uma verificação de tabela:

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

Para mostrar a diferença que isso faz nos planos de execução reais, testaremos com um SQL-Fiddle (um site extremamente ú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') ;

Vamos experimentar as 2 versões agora.


Versão 1 com DATE(timestamp) = ?

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

Explicar:

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

ROWS  FILTERED  EXTRA
6671  100       Using where; Using filesort

Ele filtra todas as (6671) linhas e, em seguida, faz uma classificação de arquivos (isso não é um problema, pois as linhas retornadas são poucas)


Versão 2 com timestamp <= ? AND timestamp < ?

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

Explicar:

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

Ele usa uma varredura de intervalo no índice e, em seguida, lê apenas as linhas correspondentes da tabela.


ótima explicação e obrigado pelo sql-fiddle. um comentário sobre seu esquema que me surpreendeu por um momento, que INDEX t_IX (timestamp, id)poderia (deveria?) apenas ser INDEX t_IX (timestamp), já que a chave primária está implícita no índice. ou há uma razão que eu não entendo para fazer isso? Eu tentei no sql-fiddle e vi o mesmo (melhor) plano de execução
natbro

1
@natbro Sim, se a tabela usa o mecanismo InnoDB, o id(porque é o PK e, portanto, o índice agrupado da tabela) é anexado ao índice de qualquer maneira. Portanto, não custa nada adicioná-lo explicitamente (e pode pegar alguns pontos cegos do otimizador). Certamente não é relevante neste caso / consulta.
ypercubeᵀᴹ

Alguém pode explicar porque timestamp < CURDATE() + INTERVAL 1 DAYé necessário?
Nightwolf

@Nightwolf porque você pode ter linhas armazenadas onde o valor do carimbo de data / hora está no futuro. A pergunta pede "apenas os registros de hoje" .
ypercubeᵀᴹ

@ TypoCubeᵀᴹ Aha, não considerou isso puramente porque timestamp não fará datas futuras. No entanto, bom ponto a ter em mente.
Nightwolf

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

é mais curto, não há necessidade de usar 'AND timestamp <CURDATE () + INTERVAL 1 DAY'

porque CURDATE () sempre retorna o dia atual

Função CURDATE () do MySQL


a) A pergunta pede "apenas os registros de hoje", e seu código também obtém datas futuras. b) Sua comparação não funciona, você deve fazê-la com DATE (timestamp). Em outras palavras: Se você corrigir sua resposta, obterá a resposta original @JohnWoo.
Katapofatico

2

De quantas maneiras podemos tirar a pele desse gato? Aqui está mais uma variante.

SELECT * FROM tableWHERE DATE (FROM_UNIXTIME ( timestamp)) = '2015-11-18';


2

Se você quiser comparar com uma data específica, pode escrever diretamente como:

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

// aqui o timestamp é o nome da coluna tendo o tipo como timestamp

ou

Para buscar a data de hoje, a função CURDATE () está disponível, então:

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

1

Basta lançá-lo em uma data:

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

1

Isso poderia ser o mais fácil na minha opinião:

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


0

No Visual Studio 2017, usando o banco de dados integrado para desenvolvimento, tive problemas com a solução fornecida atual, tive que alterar o código para fazê-lo funcionar porque gerou o erro de que DATE () não era uma função integrada.

Aqui está minha solução:

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


Você provavelmente não estava usando MySQL, mas algum outro SGBD (SQL Server, talvez?) Observe as marcas da pergunta.
ypercubeᵀᴹ
Ao utilizar nosso site, você reconhece que leu e compreendeu nossa Política de Cookies e nossa Política de Privacidade.
Licensed under cc by-sa 3.0 with attribution required.