Bagaimana cara memilih baris yang memiliki cap waktu hari ini?


104

Saya mencoba memilih hanya catatan hari ini dari tabel database.

Saat ini saya gunakan

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

Tetapi ini membutuhkan hasil selama 24 jam terakhir, dan saya memerlukannya untuk hanya memilih hasil mulai hari ini, mengabaikan waktu. Bagaimana saya dapat memilih hasil berdasarkan tanggal saja?

Jawaban:


191

gunakan DATEdanCURDATE()

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

Saya kira menggunakan DATE masih menggunakan INDEX .

lihat rencana eksekusi di DEMO


Lihat perbedaannya: SQL-Fiddle Perhatikan FILTERED = 25 di kueri ke-2.
ypercubeᵀᴹ

@ypercube oh saya melewatkan itu tetapi saya bertanya-tanya mengapa nilai ekstra Using where; Using index?
John Woo

1
Indeks digunakan untuk memilih baris. Tetapi seluruh indeks dipindai (dan semua nilai dikonversi dengan DATE () untuk mengevaluasi kondisi) dengan kueri Anda. Saya akan memperbarui jawaban saya dengan contoh yang lebih baik.
ypercubeᵀᴹ

1
Dengan segala hormat, solusi ypercube lebih baik untuk alasan kinerja, jika tabel Anda memiliki ratusan ribu baris, Anda pasti harus pergi ke arah ini
Vincent

1
yang "penting karena timestamp(dan dateseperti dalam kasus saya) adalah kata yang dipesan MySQL
Victor Ferreira

55

Jika Anda ingin indeks digunakan dan kueri tidak melakukan pemindaian tabel:

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

Untuk menunjukkan perbedaan yang dibuat pada rencana eksekusi sebenarnya, kami akan menguji dengan SQL-Fiddle (situs yang sangat membantu):

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') ;

Ayo coba 2 versi sekarang.


Versi 1 dengan DATE(timestamp) = ?

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

Menjelaskan:

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

ROWS  FILTERED  EXTRA
6671  100       Using where; Using filesort

Ini memfilter semua (6671) baris dan kemudian melakukan filesort (itu bukan masalah karena baris yang dikembalikan sedikit)


Versi 2 dengan timestamp <= ? AND timestamp < ?

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

Menjelaskan:

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

Ini menggunakan pemindaian rentang pada indeks , dan kemudian hanya membaca baris yang sesuai dari tabel.


penjelasan yang bagus dan terima kasih untuk sql-fiddle. satu komentar tentang skema Anda yang membuat saya sejenak, yang INDEX t_IX (timestamp, id)bisa (seharusnya?) begitu saja INDEX t_IX (timestamp), karena kunci utama tersirat dalam indeks. atau adakah alasan saya tidak mengerti untuk melakukan itu? saya mencobanya di sql-fiddle dan melihat rencana eksekusi yang sama (lebih baik)
natbro

1
@natbro Ya, jika tabel menggunakan mesin InnoDB, id(karena ini adalah PK dan dengan demikian indeks berkerumun dari tabel) tetap ditambahkan dalam indeks. Jadi, tidak ada salahnya untuk menambahkannya secara eksplisit (dan ini mungkin menangkap beberapa titik buta pengoptimal). Ini tentu tidak relevan dalam kasus / kueri ini.
ypercubeᵀᴹ

Adakah yang bisa menjelaskan mengapa timestamp < CURDATE() + INTERVAL 1 DAYperlu?
Nightwolf

@Nightwolf karena Anda mungkin memiliki baris yang disimpan di mana nilai stempel waktu berada di masa mendatang. Pertanyaannya menanyakan "hanya catatan hari ini" .
ypercubeᵀᴹ

@ TypoCubeᵀᴹ Aha, tidak menganggap itu murni karena stempel waktu tidak akan menunjukkan tanggal yang akan datang. Meskipun demikian hal yang baik untuk diingat.
Nightwolf

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

lebih pendek, tidak perlu menggunakan 'AND timestamp <CURDATE () + INTERVAL 1 DAY'

karena CURDATE () selalu mengembalikan hari ini

Fungsi MySQL CURDATE ()


a) Pertanyaan menanyakan "hanya catatan hari ini", dan kode Anda juga mendapatkan tanggal di masa mendatang. b) Perbandingan Anda tidak berhasil, Anda harus melakukannya dengan DATE (stempel waktu) Dengan kata lain: Jika Anda memperbaiki jawaban Anda, Anda akan mendapatkan jawaban asli @JohnWoo.
Katapofatico

2

Berapa cara kita menguliti kucing ini? Inilah varian lainnya.

PILIH * DARI tableMANA TANGGAL (FROM_UNIXTIME ( timestamp)) = '2015-11-18';


2

Jika Anda ingin membandingkan dengan tanggal tertentu, Anda bisa langsung menulisnya seperti:

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

// disini timestamp adalah nama kolom yang bertipe timestamp

atau

Untuk mengambil tanggal hari ini, tersedia fungsi CURDATE (), jadi:

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

1

Cukup kirimkan ke tanggal:

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

1

Ini bisa jadi yang paling mudah menurut saya:

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


0

Pada Visual Studio 2017, menggunakan database built-in untuk pengembangan, saya memiliki masalah dengan solusi yang diberikan saat ini, saya harus mengubah kode untuk membuatnya berfungsi karena melemparkan kesalahan bahwa DATE () bukan fungsi built-in.

Inilah solusi saya:

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


Anda mungkin tidak menggunakan MySQL tetapi beberapa DBMS lain (SQL Server mungkin?) Perhatikan tag pertanyaan.
ypercubeᵀᴹ
Dengan menggunakan situs kami, Anda mengakui telah membaca dan memahami Kebijakan Cookie dan Kebijakan Privasi kami.
Licensed under cc by-sa 3.0 with attribution required.