2016-06-20 56 views
17

ho la seguente query:OR conflitto tra le altre condizioni

SELECT * FROM `Contacts` 
WHERE `Zona` = '1' 
AND `Responsable` = '9' 
AND `AllowComercialVisit` = 'Call_Again' 
-- the problem are OR's -- 
OR `AllowComercialVisit` = 'Busy' 
OR `AllowComercialVisit` = 'Not_answered' 
-- the problem are OR's -- 
AND `DateRecall` <= '2016-06-20 13:04:52' 
AND `DateRecall` >= '2016-06-20 12:39:52' 
ORDER BY `DateRecall` ASC LIMIT 1 

Il problema è che la query voglia SOLO mostra le righe tra il primo e il secondo 'DateRecall', ma restituire tutte le righe con 'Call_Again', 'Occupato' e 'Not_answered' senza filtrare la data.

Qualsiasi soluzione sarà apprezzata!

+9

Mai, mai, * mai * mix 'OR' con 'AND' senza usare parentesi per rendere esplicito il tuo raggruppamento, in qualsiasi lingua. Anche se non è strettamente necessario in alcune situazioni, nessuno sarà in grado di capire le tue intenzioni senza di loro. – jpmc26

+2

Anche se non sono d'accordo sul fatto che "nessuno sarà in grado di capire le proprie intenzioni senza di loro", sono assolutamente d'accordo nell'usare sempre le parentesi. L'unica eccezione che faccio è quando stai facendo esattamente un confronto in lingue che lo supportano, come Python; in tutti gli altri casi, le parentesi non solo rendono più leggibile il tuo codice, ma ti proteggono dall'ordine delle operazioni (e da altri problemi più difficili da quantificare, come certe stranezze booleane in PHP che non hanno senso logico ma vengono comunque evitate in questo modo). Per le query SQL, considerare anche i livelli di indentazione per la chiarezza del nesting. – kungphu

risposta

47

Un semplice IN() risolverebbe questo:

SELECT * FROM `Contacts` 
WHERE `Zona` = '1' 
    AND `Responsable` = '9' 
    AND `AllowComercialVisit` IN ('Call_Again','Busy','Not_answered') 
    AND `DateRecall` BETWEEN '2016-06-20 12:39:52' 
         AND '2016-06-20 13:04:52' 
ORDER BY `DateRecall` ASC 
LIMIT 1 

In generale, AND ha la precedenza su OR, quando si utilizza OR provare a utilizzare parentesi ->

WHERE COND1 AND COND2 AND (COND3 OR COND4) AND COND5 

che costringerà l'ottimizzatore di seguire il vostro la precedenza e non quella di default.

+1

Non potresti usare BETWEEN per accorciare ulteriormente la query? Mi rendo conto che non fa la differenza per l'ottimizzatore, ma lo trovo più facile da leggere. – sfdcfox

12

provare la seguente query:

SELECT * FROM `Contacts` 
WHERE `Zona` = '1' 
AND `Responsable` = '9' 
AND (`AllowComercialVisit` = 'Call_Again' OR `AllowComercialVisit` = 'Busy' OR AllowComercialVisit` = 'Not_answered') 
AND `DateRecall` <= '2016-06-20 13:04:52' 
AND `DateRecall` >= '2016-06-20 12:39:52' 
ORDER BY `DateRecall` ASC 
LIMIT 1 

Basta circondano l'OR del con parentesi.

7

Cercate di gruppo OR in quanto sono legati alla stessa colonna, cioè

SELECT * FROM `Contacts` 
WHERE `Zona` = '1' 
AND `Responsable` = '9' 
AND (`AllowComercialVisit` = 'Call_Again' 
OR `AllowComercialVisit` = 'Busy' 
OR `AllowComercialVisit` = 'Not_answered') 
AND `DateRecall` <= '2016-06-20 13:04:52' 
AND `DateRecall` >= '2016-06-20 12:39:52' 
ORDER BY `DateRecall` ASC LIMIT 1 
0

È possibile utilizzare l'istruzione IN() invece di OR s:

SELECT * FROM `Contacts` 
WHERE `Zona` = '1' 
    AND `Responsable` = '9' 
    AND `AllowComercialVisit` IN('Call_Again','Busy','Not_answered') 
    AND `DateRecall` <= '2016-06-20 13:04:52' 
    AND `DateRecall` >= '2016-06-20 12:39:52' 
    ORDER BY `DateRecall` ASC LIMIT 1