Làm cách nào để chọn các hàng có dấu thời gian của ngày hiện tại?


104

Tôi đang cố gắng chỉ chọn các bản ghi của ngày hôm nay từ một bảng cơ sở dữ liệu.

Hiện tại tôi sử dụng

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

Nhưng điều này sẽ có kết quả trong 24 giờ qua và tôi cần nó để chỉ chọn kết quả từ hôm nay, bỏ qua thời gian. Làm cách nào tôi có thể chọn kết quả chỉ dựa trên ngày?

Câu trả lời:


191

sử dụng DATECURDATE()

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

Tôi đoán sử dụng DATE vẫn sử dụng INDEX .

xem kế hoạch thực hiện trên DEMO


Xem sự khác biệt: SQL-Fiddle Lưu ý FILTERED = 25 trong truy vấn thứ hai.
ypercubeᵀᴹ

@ypercube ôi tôi đã bỏ lỡ điều đó nhưng tôi đã tự hỏi tại sao giá trị lại tăng thêm Using where; Using index?
John Woo

1
Chỉ mục được sử dụng để chọn các hàng. Nhưng toàn bộ chỉ mục được quét (và tất cả các giá trị được chuyển đổi với DATE () để đánh giá điều kiện) với truy vấn của bạn. Tôi sẽ cập nhật câu trả lời của mình với một ví dụ tốt hơn.
ypercubeᵀᴹ

1
với tất cả sự tôn trọng, giải pháp ypercube là tốt hơn vì lý do hiệu suất, nếu bảng của bạn có hàng trăm ngàn dòng, bạn chắc chắn sẽ đi theo hướng này
Vincent

1
'cái' rất quan trọng vì timestamp(và datenhư trong trường hợp của tôi) là một MySQL từ dành riêng
Victor Ferreira

55

Nếu bạn muốn một chỉ mục được sử dụng và truy vấn không thực hiện quét bảng:

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

Để cho thấy sự khác biệt mà điều này tạo ra đối với các kế hoạch thực thi thực tế, chúng tôi sẽ kiểm tra bằng SQL-Fiddle (một trang web cực kỳ hữu ích):

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

Hãy thử 2 phiên bản ngay bây giờ.


Phiên bản 1 với DATE(timestamp) = ?

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

Giải thích:

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

ROWS  FILTERED  EXTRA
6671  100       Using where; Using filesort

lọc tất cả (6671) hàng và sau đó sắp xếp tệp (đó không phải là vấn đề vì các hàng trả về rất ít)


Phiên bản 2 với timestamp <= ? AND timestamp < ?

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

Giải thích:

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

Nó sử dụng quét phạm vi trên chỉ mục , và sau đó chỉ đọc các hàng tương ứng từ bảng.


lời giải thích tuyệt vời và cảm ơn về sql-fiddle. một nhận xét trên lược đồ của bạn đã khiến tôi phải ngỡ ngàng, điều đó INDEX t_IX (timestamp, id)có thể (nên?) chỉ là INDEX t_IX (timestamp), vì khóa chính được ngụ ý trong chỉ mục. hay có lý do gì mà tôi không hiểu để làm điều đó? tôi đã cố gắng nó trong sql-fiddle và thấy như nhau (tốt hơn) kế hoạch thực hiện
natbro

1
@natbro Có, nếu bảng sử dụng công cụ InnoDB, id(vì nó là PK và do đó là chỉ mục nhóm của bảng) vẫn được thêm vào chỉ mục. Vì vậy, không có hại gì khi thêm nó một cách rõ ràng (và nó có thể bắt gặp một số điểm mù của trình tối ưu hóa). Nó chắc chắn không liên quan trong trường hợp / truy vấn này.
ypercubeᵀᴹ

Bất cứ ai có thể giải thích tại sao timestamp < CURDATE() + INTERVAL 1 DAYlà cần thiết?
Nightwolf

@Nightwolf vì bạn có thể có các hàng được lưu trữ ở vị trí giá trị dấu thời gian trong tương lai. Câu hỏi yêu cầu "chỉ ghi ngày hôm nay" .
ypercubeᵀᴹ

@ TypoCubeᵀᴹ Aha, không xem xét điều đó hoàn toàn vì dấu thời gian sẽ không hiển thị các ngày trong tương lai. Tuy nhiên, điểm tốt cần ghi nhớ.
Nightwolf

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

nó ngắn hơn, không cần sử dụng 'AND thời gian <CURDATE () + INTERVAL 1 DAY'

vì CURDATE () luôn trả về ngày hiện tại

Hàm MySQL CURDATE ()


a) Câu hỏi yêu cầu "chỉ các bản ghi của ngày hôm nay" và mã của bạn cũng nhận được các ngày trong tương lai. b) So sánh của bạn không hoạt động, bạn phải thực hiện với DATE (dấu thời gian) Nói cách khác: Nếu bạn sửa câu trả lời của mình, bạn sẽ nhận được câu trả lời gốc của @JohnWoo.
Katapofatico

2

Có bao nhiêu cách chúng ta có thể lột da con mèo này? Đây là một biến thể khác.

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


2

Nếu bạn muốn so sánh với một ngày cụ thể, Bạn có thể viết trực tiếp nó như:

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

// ở đây dấu thời gian là tên của cột có kiểu là dấu thời gian

hoặc là

Để tìm nạp ngày hôm nay, hàm CURDATE () khả dụng, vì vậy:

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

1

Chỉ cần truyền nó đến một ngày:

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

1

Điều này có thể là dễ nhất theo ý kiến ​​của tôi:

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


0

Trên Visual Studio 2017, bằng cách sử dụng cơ sở dữ liệu tích hợp sẵn để phát triển, tôi đã gặp sự cố với giải pháp đã cho hiện tại, tôi phải thay đổi mã để làm cho nó hoạt động vì nó gây ra lỗi DATE () không phải là một hàm được tích hợp sẵn.

Đây là giải pháp của tôi:

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


Bạn có thể không sử dụng MySQL nhưng một số DBMS khác (có thể là SQL Server?) Lưu ý các thẻ của câu hỏi.
ypercubeᵀᴹ
Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.