SQL - avendo VS dove


202

Ho le seguenti due tabelle:

1. Lecturers (LectID, Fname, Lname, degree).
2. Lecturers_Specialization (LectID, Expertise).

Voglio trovare il docente con la maggiore specializzazione. Quando provo questo, non funziona:

SELECT
  L.LectID, 
  Fname, 
  Lname 
FROM Lecturers L, 
     Lecturers_Specialization S
WHERE L.LectID = S.LectID
AND COUNT(S.Expertise) >= ALL (SELECT
  COUNT(Expertise)
FROM Lecturers_Specialization
GROUP BY LectID);

Ma quando provo questo, funziona:

SELECT
  L.LectID,
  Fname,
  Lname 
FROM Lecturers L,
     Lecturers_Specialization S
WHERE L.LectID = S.LectID
GROUP BY L.LectID,
         Fname,
         Lname 
HAVING COUNT(S.Expertise) >= ALL (SELECT
  COUNT(Expertise)
FROM Lecturers_Specialization
GROUP BY LectID); 

Qual è la ragione? Grazie.


2
Puoi chiarire quale versione di SQL stai utilizzando (MySQL, MS SQL, PostgreSQL, Oracle, ecc.). Inoltre, quando dici "non funziona", vuoi dire che i risultati non sono come previsto o che c'è un errore di compilazione / analisi?
jklemmack,

2
Perché usi ALL invece di MAX ?. C'è qualche vantaggio?
skan

Risposte:


352

WHEREla clausola introduce una condizione su singole righe ; HAVINGla clausola introduce una condizione sulle aggregazioni , ovvero i risultati della selezione in cui un singolo risultato, come conteggio, media, min, max o somma, è stato prodotto da più righe. La query richiede un secondo tipo di condizione (ovvero una condizione su un'aggregazione) quindi HAVINGfunziona correttamente.

Come regola generale, utilizzare WHEREprima GROUP BYe HAVINGdopo GROUP BY. È una regola piuttosto primitiva, ma è utile in oltre il 90% dei casi.

Mentre ci sei, potresti voler riscrivere la tua query usando la versione ANSI del join:

SELECT  L.LectID, Fname, Lname
FROM Lecturers L
JOIN Lecturers_Specialization S ON L.LectID=S.LectID
GROUP BY L.LectID, Fname, Lname
HAVING COUNT(S.Expertise)>=ALL
(SELECT COUNT(Expertise) FROM Lecturers_Specialization GROUP BY LectID)

Ciò eliminerebbe l' WHEREuso di una condizione di join theta .


40

HAVINGopera su aggregati. Poiché COUNTè una funzione aggregata, non è possibile utilizzarla in una WHEREclausola.

Ecco alcune letture da MSDN su funzioni aggregate.


30

Prima di tutto dovremmo conoscere l'ordine di esecuzione delle clausole, ovvero DA> DOVE> Raggruppa> HAVING> DISTINCT> SELEZIONA> ORDINA PER. Poiché la clausola WHERE viene eseguita prima della clausola GROUP BY, i record non possono essere filtrati applicando WHERE ai record applicati GROUP BY .

"HAVING è uguale alla clausola WHERE ma viene applicato ai record raggruppati".

prima la clausola WHERE recupera i record in base alla condizione, quindi la clausola GROUP BY li raggruppa di conseguenza e quindi la clausola HAVING recupera i record del gruppo in base alla condizione di avere.


Questo ordine di operazioni viene sempre utilizzato? Che cosa succede se Query Optimizer modifica l'ordine?
MSIS,

1
@MSIS anche se l'ottimizzatore di query modifica l'ordine, il risultato dovrebbe essere lo stesso di questo ordine. È un ordine logico.
Stephen

18
  1. La clausola WHERE può essere utilizzata con le istruzioni SELECT, INSERT e UPDATE, mentre HAVING può essere utilizzato solo con l'istruzione SELECT.

  2. DOVE filtra le righe prima dell'aggregazione (GROUP BY), mentre HAVING filtra i gruppi dopo aver eseguito le aggregazioni.

  3. La funzione aggregata non può essere utilizzata nella clausola WHERE se non in una subquery contenuta nella clausola HAVING, mentre le funzioni aggregate possono essere utilizzate nella clausola HAVING.

fonte


11

Non ho visto un esempio di entrambi in una query. Quindi questo esempio potrebbe aiutare.

  /**
INTERNATIONAL_ORDERS - table of orders by company by location by day
companyId, country, city, total, date
**/

SELECT country, city, sum(total) totalCityOrders 
FROM INTERNATIONAL_ORDERS with (nolock)
WHERE companyId = 884501253109
GROUP BY country, city
HAVING country = 'MX'
ORDER BY sum(total) DESC

Questo filtra prima la tabella per companyId, quindi la raggruppa (per paese e città) e la filtra ulteriormente fino alle sole aggregazioni di città del Messico. La societàId non era necessaria nell'aggregazione, ma siamo stati in grado di utilizzare DOVE per filtrare solo le righe che volevamo prima di usare GROUP BY.


non è un buon esempio in quanto potresti convertire: `DOVE ID azienda = 884501253109 GRUPPO PER paese, città HAVING country = 'MX'` in: `DOVE azienda ID = 884501253109, paese = 'MX' GROUP BY
città`

Se hai semplicemente suggerito di spostare il filtro [country] su WHERE, la query verrebbe errata da SELECT [country], poiché [country] non è più incluso nell'aggregazione GROUP BY, quindi non può essere selezionato.
Nhan,

Il tuo punto sull'ottimizzazione viene preso spostando [paese] su WHERE in quanto si tratterebbe di un set di dati più piccolo su GROUP BY con successivo. Naturalmente questo è solo un esempio per illustrare i possibili usi. Possiamo passare alla somma HAVING (totale)> 1000 e sarebbe un caso del tutto valido includere WHERE e HAVING.
Nhan,

9

Non è possibile utilizzare la clausola where con funzioni di aggregazione perché in cui recupera i record in base alla condizione, va nel record della tabella in base al record e quindi recupera il record in base alla condizione che abbiamo dato. Quindi quella volta non possiamo dove clausola. Pur avendo la clausola funziona sul set di risultati che finalmente otteniamo dopo aver eseguito una query.

Quesito di esempio:

select empName, sum(Bonus) 
from employees 
order by empName 
having sum(Bonus) > 5000;

Ciò memorizzerà il set di risultati in una memoria temporanea, quindi la clausola clausola eseguirà il suo lavoro. Quindi possiamo facilmente usare le funzioni aggregate qui.


2
Penso che non possiamo usare la clausola HAVING senza la clausola GROUP BY. Posizione della clausola HAVING - SELEZIONA -> DA -> DOVE -> Raggruppa per -> HAVING -> ORDINA PER
Morez

4

1. Possiamo usare la funzione aggregata con la clausola HAVING non con la clausola WHERE, ad es. Min, max, avg.

2. La clausola WHERE elimina la tupla record dalla tupla La clausola HAVING elimina l'intero gruppo dalla raccolta di gruppi

Principalmente HAVING viene utilizzato quando si hanno gruppi di dati e WHERE viene utilizzato quando si hanno dati in righe.

Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.