2014-12-10 3 views
9

Sto cercando di trovare un valore datetime in un database mysql che corrisponde alla corrispondenza più vicina a un datetime che ho specificato, sto riscontrando qualche problema.Trova la data/ora più vicina a data/ora specificata nella query mysql

Il seguente pseudo codice è quello che voglio ottenere:

SELECT one FROM table WHERE datetimefield is closest to "2014-12-10 09:45:00" LIMIT 1 

Grazie in anticipo

EDIT

Grazie per le risposte finora, come si scopre la query è un po 'più complicato di quanto pensassi inizialmente per ottenere il risultato desiderato, il metodo ABS funziona alla grande con alcune aggiunte.

La prossima domanda è, è comunque necessario ridurre i requisiti di prestazione per la seguente query?

SELECT DISTINCT timegenerated, *other values* 
FROM table1 e INNER JOIN table2 dt 
ON e.circuit = dt.circuit 
WHERE dt.circuit IN ("2", "3", "4", "5", "6", "7", "8") 
AND e.circuit != 1 
AND dt.siteid = 435 
ORDER BY ABS(TIMESTAMPDIFF(MINUTE, timegenerated, "2014-12-09 14:15:00")) LIMIT 7 

O incorprate in modo che corrisponda più date come ho bisogno di essere in grado di eguagliare più datetimes specifici (forse fino a 90 giorni) è attualmente in fase di esecuzione per ogni singolo datetime da un altro array, ma mi rendo conto questo non è ottimale La query viene creata dinamicamente in PHP.

Il tempo di interrogazione è attualmente di circa 1,1 secondi per query, quindi eseguire 30 volte o più diventa problematico, la tabella ha centinaia di migliaia di righe.

Molte grazie ancora!

risposta

23

L'idea chiave è quella di utilizzare order by e limit:

Se si desidera che il più vicino prima:

SELECT one 
FROM table 
WHERE datetimefield <= '2014-12-10 09:45:00' 
ORDER BY datetimefield DESC 
LIMIT 1; 

Se si desidera che il più vicino, in entrambe le direzioni, quindi utilizzare TIMESTAMPDIFF():

ORDER BY abs(TIMESTAMPDIFF(second, datetimefield, '2014-12-10 09:45:00')) 
LIMIT 1 
+0

Grazie per questo, ho aggiornato il OP con una query aggiornata che funziona ma è molto performante se vuoi essere così gentile da far luce su di esso, esulta –

+1

@JackHayfield. . . Quella porzione modificata dovrebbe essere un'altra domanda, non un addendum su questa domanda. –

4

Usa ABS()

SELECT one FROM table 
ORDER BY ABS(`datetimefield` - '2014-12-10 09:45:00') LIMIT 1 

Ciò restituirà la riga con la differenza più bassa, quella più vicina.

3

L'utilizzo di abs() impedisce l'utilizzo di un indice datetimefield. Propongo di avere uno selezionare per il più vicino prima e una selezione per il più vicino dopo, sia utilizzando l'indice, e raccogliendo il più vicino dei quali in seguito:

create table `table` (datetimefield datetime key, one varchar(99)); 
insert into `table` values 
    ('2014-06-01', 'a'), ('2014-12-01', 'b'), 
    ('2015-01-01', 'c'), ('2015-02-01', 'd'); 

set @d = '2014-12-10 09:45:00'; 

select * from 
(
    (select *, TIMESTAMPDIFF(SECOND, @d, datetimefield) as diff 
    from `table` where datetimefield >= @d 
    order by datetimefield asc limit 1 
) 
    union 
    (select *, TIMESTAMPDIFF(SECOND, datetimefield, @d) as diff 
    from `table` where datetimefield < @d 
    order by datetimefield desc limit 1 
) 
) x 
order by diff 
limit 1; 

http://sqlfiddle.com/#!2/bddb4/1

+0

lo rendi più complicato .. –

+1

Più complicato non è necessariamente una cosa negativa se si tratta di prestazioni migliori ... che è il punto del suo post. – thaspius