Wie wähle ich Zeilen mit dem Zeitstempel des aktuellen Tages aus?

104

Ich versuche, nur die heutigen Datensätze aus einer Datenbanktabelle auszuwählen.

Derzeit benutze ich

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

Dies erfordert jedoch Ergebnisse für die letzten 24 Stunden, und ich brauche sie, um nur Ergebnisse von heute auszuwählen und die Zeit zu ignorieren. Wie kann ich Ergebnisse nur anhand des Datums auswählen?

Jackie Honson
quelle

Antworten:

191

benutze DATEundCURDATE()

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

Ich denke, mit verwendet wird DATE immer noch INDEX .

Siehe den Ausführungsplan auf der DEMO

John Woo
quelle
Sehen Sie den Unterschied: SQL-Fiddle Beachten Sie FILTERED = 25 in der 2. Abfrage.
Ypercubeᵀᴹ
@ypercube oh ich habe das verpasst, aber ich habe mich gefragt, warum der Wert auf extra ist Using where; Using index?
John Woo
1
Der Index wird zur Auswahl der Zeilen verwendet. Der gesamte Index wird jedoch mit Ihrer Abfrage gescannt (und alle Werte werden mit DATE () konvertiert, um die Bedingung zu bewerten). Ich werde meine Antwort mit einem besseren Beispiel aktualisieren.
Ypercubeᵀᴹ
1
Bei allem Respekt ist die ypercube-Lösung aus Leistungsgründen besser. Wenn Ihre Tabelle Hunderttausende von Zeilen enthält, sollten Sie auf jeden Fall in diese Richtung gehen
Vincent
1
Die `` sind wichtig, weil timestamp(und datewie in meinem Fall) ein von MySQL reserviertes Wort ist
Victor Ferreira
55

Wenn Sie möchten, dass ein Index verwendet wird und die Abfrage keinen Tabellenscan durchführt:

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

Um den Unterschied zu zeigen, den dies für die tatsächlichen Ausführungspläne bedeutet, testen wir mit einer SQL-Fiddle (eine äußerst hilfreiche Site):

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

Probieren wir jetzt die 2 Versionen aus.


Version 1 mit DATE(timestamp) = ?

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

Erklären:

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

ROWS  FILTERED  EXTRA
6671  100       Using where; Using filesort

Es filtert alle (6671) Zeilen und führt dann eine Dateisortierung durch (dies ist kein Problem, da nur wenige Zeilen zurückgegeben werden).


Version 2 mit timestamp <= ? AND timestamp < ?

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

Erklären:

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

Es verwendet einen Bereichsscan für den Index und liest dann nur die entsprechenden Zeilen aus der Tabelle.

ypercubeᵀᴹ
quelle
tolle Erklärung und danke für die SQL-Geige. Ein Kommentar zu Ihrem Schema, der mich für einen Moment geworfen hat, INDEX t_IX (timestamp, id)könnte (sollte?) einfach sein INDEX t_IX (timestamp), da der Primärschlüssel im Index impliziert ist. oder gibt es einen Grund, warum ich das nicht verstehe? Ich habe es in SQL-Fiddle versucht und sah den gleichen (besseren) Ausführungsplan
Natbro
1
@natbro Ja, wenn die Tabelle die InnoDB-Engine verwendet, wird die id(da es sich um die PK und damit um den Clustered-Index der Tabelle handelt) trotzdem an den Index angehängt. Es tut also nicht weh, es explizit hinzuzufügen (und es kann einige blinde Flecken des Optimierers erkennen). Es ist in diesem Fall / Abfrage sicherlich nicht relevant.
Ypercubeᵀᴹ
Kann jemand erklären, warum timestamp < CURDATE() + INTERVAL 1 DAYdas notwendig ist?
Nightwolf
@Nightwolf, da möglicherweise Zeilen gespeichert sind, in denen der Zeitstempelwert in der Zukunft liegt. Die Frage fragt nach "nur den heutigen Aufzeichnungen" .
Ypercubeᵀᴹ
@ TypoCubeᵀᴹ Aha, habe das nicht berücksichtigt, nur weil der Zeitstempel keine zukünftigen Daten enthält. Trotzdem ein guter Punkt zu beachten.
Nightwolf
11
SELECT * FROM `table` WHERE timestamp >= CURDATE()

es ist kürzer, es muss nicht 'AND timestamp <CURDATE () + INTERVAL 1 DAY' verwendet werden.

weil CURDATE () immer den aktuellen Tag zurückgibt

MySQL CURDATE () Funktion

Hamed Persia
quelle
a) Die Frage fragt nach "nur den heutigen Aufzeichnungen", und Ihr Code erhält auch zukünftige Daten. b) Ihr Vergleich funktioniert nicht, Sie müssen ihn mit DATE (Zeitstempel) durchführen. Mit anderen Worten: Wenn Sie Ihre Antwort korrigieren, erhalten Sie die ursprüngliche Antwort von @JohnWoo.
Katapofatico
2

Wie viele Möglichkeiten können wir diese Katze häuten? Hier ist noch eine andere Variante.

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

stefgosselin
quelle
2

Wenn Sie mit einem bestimmten Datum vergleichen möchten, können Sie es direkt wie folgt schreiben:

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

// hier ist der Zeitstempel der Name der Spalte mit dem Typ als Zeitstempel

oder

Zum Abrufen des heutigen Datums steht die Funktion CURDATE () zur Verfügung.

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

Wirf es einfach auf ein Datum:

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

Dies könnte meiner Meinung nach am einfachsten sein:

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

Oder Sie können die Alternative CURRENT_DATE mit demselben Ergebnis verwenden:

SELECT * FROM yourtable WHERE created >= CURRENT_DATE

Beispiele aus database.guide

Kochauf
quelle
0

In Visual Studio 2017 musste ich unter Verwendung der integrierten Datenbank für die Entwicklung Probleme mit der aktuell angegebenen Lösung haben. Ich musste den Code ändern, damit er funktioniert, da der Fehler ausgegeben wurde, dass DATE () keine integrierte Funktion war.

Hier ist meine Lösung:

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

Cesar Bourdain Costa
quelle
Sie haben wahrscheinlich nicht MySQL verwendet, sondern ein anderes DBMS (vielleicht SQL Server?). Beachten Sie die Tags der Frage.
Ypercubeᵀᴹ