จะเลือกแถวที่มีการประทับเวลาของวันปัจจุบันได้อย่างไร?


105

ฉันพยายามเลือกเฉพาะระเบียนของวันนี้จากตารางฐานข้อมูล

ปัจจุบันฉันใช้

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

แต่สิ่งนี้ต้องใช้ผลลัพธ์ในช่วง 24 ชั่วโมงที่ผ่านมาและฉันต้องการให้เลือกเฉพาะผลลัพธ์จากวันนี้โดยไม่สนใจเวลา ฉันจะเลือกผลลัพธ์ตามวันที่เท่านั้นได้อย่างไร?

คำตอบ:


193

ใช้DATEและCURDATE()

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

ผมคิดว่าใช้DATE ยังคงใช้ INDEX

ดูแผนการดำเนินการใน DEMO


ดูความแตกต่าง: SQL-Fiddleสังเกตว่า FILTERED = 25 ในแบบสอบถามที่ 2
ypercubeᵀᴹ

@ypercube โอ้ฉันคิดถึง แต่ผมสงสัยว่าทำไมค่าพิเศษUsing where; Using index?
John Woo

1
ดัชนีใช้เพื่อเลือกแถว แต่ดัชนีทั้งหมดจะถูกสแกน (และค่าทั้งหมดจะถูกแปลงด้วย DATE () เพื่อประเมินเงื่อนไข) ด้วยข้อความค้นหาของคุณ ฉันจะอัปเดตคำตอบพร้อมตัวอย่างที่ดีกว่า
ypercubeᵀᴹ

1
ด้วยความเคารพทุกประการโซลูชัน ypercube ดีกว่าด้วยเหตุผลด้านประสิทธิภาพหากตารางของคุณมีหลายแสนบรรทัดคุณควรไปในทิศทางนี้อย่างแน่นอน
Vincent

1
`` มีความสำคัญเพราะtimestamp(และdateในกรณีของฉัน) เป็นคำสงวนของ MySQL
Victor Ferreira

58

หากคุณต้องการใช้ดัชนีและแบบสอบถามไม่ต้องทำการสแกนตาราง:

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

เพื่อแสดงความแตกต่างที่เกิดขึ้นกับแผนการดำเนินการจริงเราจะทดสอบด้วยSQL-Fiddle (ไซต์ที่มีประโยชน์อย่างยิ่ง):

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

มาลอง 2 เวอร์ชั่นเลย


เวอร์ชัน 1 กับ DATE(timestamp) = ?

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

อธิบาย:

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

ROWS  FILTERED  EXTRA
6671  100       Using where; Using filesort

มันกรองทั้งหมด (6671) แถวแล้วไม่ filesort (ที่ไม่ได้เป็นปัญหาเป็นแถวกลับมีน้อย)


เวอร์ชัน 2 กับ timestamp <= ? AND timestamp < ?

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

อธิบาย:

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

ใช้การสแกนช่วงบนดัชนีจากนั้นอ่านเฉพาะแถวที่เกี่ยวข้องจากตาราง


คำอธิบายที่ดีและขอบคุณสำหรับ sql-fiddle ความคิดเห็นหนึ่งในสคีมาของคุณที่ทำให้ฉันรู้สึกชั่วครู่ซึ่งINDEX t_IX (timestamp, id)อาจเป็นไปได้ (ควร?) INDEX t_IX (timestamp)เนื่องจากคีย์หลักมีนัยในดัชนี หรือมีเหตุผลที่ฉันไม่เข้าใจในการทำเช่นนั้น? ฉันลองใช้ sql-fiddle และเห็นแผนการดำเนินการเดียวกัน (ดีกว่า)
natbro

1
@natbro ใช่ถ้าตารางใช้เครื่องมือ InnoDB id(เนื่องจากเป็น PK และด้วยเหตุนี้ดัชนีคลัสเตอร์ของตาราง) จะถูกต่อท้ายในดัชนี ดังนั้นจึงไม่เจ็บที่จะเพิ่มอย่างชัดเจน (และอาจพบจุดบอดของเครื่องมือเพิ่มประสิทธิภาพบางอย่าง) ไม่เกี่ยวข้องกับกรณี / แบบสอบถามนี้อย่างแน่นอน
ypercubeᵀᴹ

ใครสามารถอธิบายได้ว่าทำไมจึงtimestamp < CURDATE() + INTERVAL 1 DAYจำเป็น?
Nightwolf

@Nightwolf เนื่องจากคุณอาจมีแถวที่เก็บไว้ซึ่งค่าการประทับเวลาอยู่ในอนาคต คำถามที่ถามหา"บันทึกเฉพาะวันนี้"
ypercubeᵀᴹ

@ TypoCubeᵀᴹ Aha ไม่ได้พิจารณาเรื่องนั้นอย่างหมดจดเพราะการประทับเวลาจะไม่ระบุวันที่ในอนาคต อย่างไรก็ตามจุดที่ดีที่ควรทราบ
Nightwolf

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

สั้นกว่าไม่จำเป็นต้องใช้ 'AND timestamp <CURDATE () + INTERVAL 1 DAY'

เนื่องจาก CURDATE () ส่งกลับวันปัจจุบันเสมอ

MySQL CURDATE () ฟังก์ชัน


1
ก) คำถามจะถามว่า "เฉพาะบันทึกของวันนี้" และรหัสของคุณจะได้รับวันที่ในอนาคตด้วย b) การเปรียบเทียบของคุณไม่ได้ผลคุณต้องทำด้วย DATE (การประทับเวลา) กล่าวอีกนัยหนึ่ง: หากคุณแก้ไขคำตอบคุณจะได้รับคำตอบเดิมของ @JohnWoo
Katapofatico

3

เราสามารถถลกหนังแมวได้กี่วิธี? นี่เป็นอีกหนึ่งตัวแปร

เลือก * จากtableวันที่ (FROM_UNIXTIME ( timestamp)) = '2015-11-18';


3

หากคุณต้องการเปรียบเทียบกับวันใดวันหนึ่งคุณสามารถเขียนได้โดยตรงเช่น:

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

// ในที่นี้การประทับเวลาคือชื่อของคอลัมน์ที่มีประเภทเป็นการประทับเวลา

หรือ

สำหรับการดึงข้อมูลวันนี้ฟังก์ชัน CURDATE () จะพร้อมใช้งานดังนั้น:

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




1

ใน Visual Studio 2017 โดยใช้ฐานข้อมูลในตัวสำหรับการพัฒนาฉันมีปัญหากับโซลูชันที่กำหนดในปัจจุบันฉันต้องเปลี่ยนรหัสเพื่อให้ใช้งานได้เนื่องจากมีข้อผิดพลาดที่ DATE () ไม่ใช่ฟังก์ชันในตัว

นี่คือทางออกของฉัน:

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


คุณอาจไม่ได้ใช้ MySQL แต่ DBMS อื่น ๆ (อาจเป็น SQL Server?) สังเกตแท็กของคำถาม
ypercubeᵀᴹ
โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.