Jaka jest różnica między POSIADANIEM a GDZIE?


260

Muszę googlować w niewłaściwy sposób lub mam głupi moment.

Jaka jest różnica między HAVINGi WHEREw SQL SELECToświadczeniu?

EDYCJA: Oznacziłem odpowiedź Stevena jako poprawną, ponieważ zawierała ona kluczową informację w linku:

Gdy GROUP BYnie jest używany, HAVINGzachowuje się jak WHEREklauzula

Sytuacja, w której widziałem, WHEREnie miała miejsca GROUP BYi właśnie tam zaczęło się moje zamieszanie. Oczywiście, dopóki się tego nie dowiesz, nie możesz podać tego w pytaniu.


43
Cytowana linia wcale nie jest kluczem. Kluczowym bitem, jak wskazał wcm , jest to, że HAVINGjest to filtr po agregacji, podczas gdy WHEREjest to filtr przed agregacją.
Nick Chammas,

ten link pomógł mi lepiej to zrozumieć niż wszystkie poniższe komentarze, pomyślałem, że ktoś może uzyskać pomoc z tego codeproject.com/Articles/25258/…
Lijin Durairaj

Odpowiedzi:


93

HAVING określa warunek wyszukiwania dla grupy lub funkcji agregującej używanej w instrukcji SELECT.

Źródło


368

MAJĄCE: służy do sprawdzania warunków po agregacji.
GDZIE: służy do sprawdzania warunków przed agregacją.

Ten kod:

select City, CNT=Count(1)
From Address
Where State = 'MA'
Group By City

Daje tabelę wszystkich miast w MA i liczbę adresów w każdym mieście.

Ten kod:

select City, CNT=Count(1)
From Address
Where State = 'MA'
Group By City
Having Count(1)>5

Daje tabelę miast w MA z więcej niż 5 adresami i liczbą adresów w każdym mieście.


7
To powinna być zaakceptowana odpowiedź. Rozróżnienie między „posiadaniem” a „gdzie” wyjaśnia to natychmiast.
Paul

27

Różnica numer jeden dla mnie: gdyby HAVINGzostała usunięta z języka SQL, życie trwałoby mniej więcej tak jak wcześniej. Z pewnością zapytania mniejszościowe musiałyby zostać przepisane przy użyciu tabeli pochodnej, CTE itp., Ale w rezultacie byłyby łatwiejsze do zrozumienia i utrzymania. Być może konieczne będzie przepisanie kodu optymalizującego sprzedawcę, aby uwzględnić to, co ponownie stanowi okazję do poprawy w branży.

Zastanówmy się teraz przez chwilę nad usunięciem WHEREz języka. Tym razem większość istniejących zapytań musiałaby zostać przepisana bez oczywistej alternatywnej konstrukcji. Kodery musiałyby być kreatywne, np. Łączyć wewnętrznie do tabeli, która zawiera dokładnie jeden wiersz (np. DUALW Oracle), używając ONklauzuli do symulacji poprzedniej WHEREklauzuli. Takie konstrukcje byłyby wymyślone; byłoby oczywiste, że czegoś brakowało w języku i sytuacja byłaby gorsza.

TL; DR moglibyśmy stracić HAVINGjutro i nie byłoby nic gorszego, być może lepszego, ale nie można tego samego powiedzieć WHERE.


Z odpowiedzi tutaj wynika, że ​​wielu ludzi nie zdaje sobie sprawy, że HAVINGklauzula może być używana bez GROUP BYklauzuli. W takim przypadku HAVINGklauzula jest stosowana do całego wyrażenia tabeli i wymaga, aby w niej występowały tylko stałe SELECT. Zazwyczaj HAVINGklauzula będzie obejmować agregaty.

Jest to bardziej przydatne niż się wydaje. Na przykład rozważ to zapytanie, aby sprawdzić, czy namekolumna jest unikalna dla wszystkich wartości w T:

SELECT 1 AS result
  FROM T
HAVING COUNT( DISTINCT name ) = COUNT( name );

Istnieją tylko dwa możliwe wyniki: jeśli HAVINGklauzula jest prawdziwa, wynikiem będzie pojedynczy wiersz zawierający wartość 1, w przeciwnym razie wynikiem będzie pusty zbiór.


Czy byłoby to równoważne z „SELECT COUNT (DISTINCT name) = COUNT (name) FROM T”?
MSpreij

@MSpreij Nie wiem, czy to działa dla Ciebie, ale nie działa na SQL Server 2005, ale pierwszy działa
Joe

22

Klauzula HAVING została dodana do SQL, ponieważ słowa kluczowego WHERE nie można było używać z funkcjami agregującymi.

Sprawdź ten link w3schools, aby uzyskać więcej informacji

Składnia:

SELECT column_name, aggregate_function(column_name)
FROM table_name
WHERE column_name operator value
GROUP BY column_name
HAVING aggregate_function(column_name) operator value

Zapytanie takie jak to:

SELECT column_name, COUNT( column_name ) AS column_name_tally
  FROM table_name
 WHERE column_name < 3
 GROUP 
    BY column_name
HAVING COUNT( column_name ) >= 3;

... można przepisać przy użyciu tabeli pochodnej (z pominięciem HAVING) w następujący sposób:

SELECT column_name, column_name_tally
  FROM (
        SELECT column_name, COUNT(column_name) AS column_name_tally
          FROM table_name
         WHERE column_name < 3
         GROUP 
            BY column_name
       ) pointless_range_variable_required_here
 WHERE column_name_tally >= 3;

3
Nieco spóźniłeś się na sedno: HAVINGzostał dodany, ponieważ tabele pochodne nie zostały dodane do języka i dopóki nie były SQL, nie były relacyjnie kompletne, a gdy nieuchronnie HAVINGstały się zbędne.
poniedziałek

21

Różnica między nimi polega na relacji do klauzuli GROUP BY:

  • GDZIE jest przed GROUP BY; SQL ocenia klauzulę WHERE przed grupowaniem rekordów.

  • POSIADA po GROUP BY; SQL ocenia HAVING po grupowaniu rekordów.

wybierz diagram instrukcji

Bibliografia


Ponieważ GROUP BY i HAVING są opcjonalne, schemat pokazuje oba przypadki, wystarczy postępować zgodnie ze strzałkami.
Paul Sweatte

Przykładowe zapytanie z mojej odpowiedzi na to pytanie: SELECT 1 AS result FROM T HAVING...- na twoim diagramie nie mogę się dostać HAVINGbez przejścia, GROUP BYale moje doskonale poprawne i przydatne zapytanie nie ma GROUP BY. Drobny punkt: nie masz możliwości włączenia literalnych wartości do SELECTklauzuli.
poniedziałek

@onedaywhen Skoro wiesz o domyślnej grupie GROUP BY, dlaczego o niej nie wspomniałeś? Czy wiesz, czy takie zachowanie jest tym, czego oczekujesz, czy nie?
Paul Sweatte

Sądzę, że cytujesz mnie poza kontekstem. Pytanie dotyczyło oczywistego odchylenia mySQL od Standardu, wszystkie oprócz ostatniego akapitu mojej odpowiedzi opisuje zachowanie Standard, a ostatnie nawiązują do „niejawnej klauzuli GROUP BY wspomnianej w innych odpowiedziach ”. Czy mówisz, że twój diagram ma na celu opisanie (wszystkich) zachowań niejawnych? Czy nie byłoby bardziej użyteczne trzymać się tylko kodu, który trzeba napisać, aby uzyskać pożądane zachowanie?
dniu

... Nie wiem, do czego się odwołujesz w drugim linku. Pożądanym rezultatem jest naprawienie diagramu, aby pokazać prawidłową (wyraźną) ścieżkę, o której wspomniałem. Pomyśl o tym: schemat obejmuje całe zapytanie, ale pytanie dotyczy tylko tej WHERE->HAVINGczęści, więc myślę, że należy zwrócić szczególną uwagę na szczegóły. Jeśli uważasz, że moja odpowiedź jest błędna, edytuj ją lub dodaj sugerowaną korektę w komentarzach.
poniedziałek

12

HAVINGjest używany, gdy używasz agregatu, takiego jak GROUP BY.

SELECT edc_country, COUNT(*)
FROM Ed_Centers
GROUP BY edc_country
HAVING COUNT(*) > 1
ORDER BY edc_country;

8

GDZIE jest stosowane jako ograniczenie zestawu zwracanego przez SQL; wykorzystuje wbudowane operacje SQL i indeksy i dlatego jest najszybszym sposobem filtrowania zestawów wyników. Zawsze używaj GDZIE, gdy to możliwe.

HAVING jest niezbędny w przypadku niektórych filtrów agregujących. Filtruje zapytanie PO pobraniu, zmontowaniu i posortowaniu wyników przez sql. Dlatego jest znacznie wolniejszy niż GDZIE i należy go unikać, z wyjątkiem sytuacji, które tego wymagają.

SQL Server pozwoli ci uniknąć używania HAVING nawet wtedy, gdy GDZIE byłoby znacznie szybciej. Nie rób tego


Obsługa tabel pochodnych w języku SQL oznacza, że ​​twierdzenie „HAVING jest konieczne w przypadku niektórych filtrów agregujących” jest fałszywe.
onedaywhen

1
Trafne spostrzeżenie. W ciągu trzech lat, odkąd napisałem tę odpowiedź, z pewnością migrowałem do korzystania z tabel pochodnych, w których wcześniej używałbym HAVING. Nie zastanawiałem się nad pytaniem, czy HAVING wciąż ma jakieś sensowne przypadki użycia. Nie wiem też, czy tabela pochodna będzie ogólnie działać lepiej niż HAVING.
davidcl

7

Klauzula WHERE nie działa w przypadku funkcji agregujących
oznacza: nie należy używać takiej premii: nazwa tabeli

SELECT name  
FROM bonus  
GROUP BY name  
WHERE sum(salary) > 200  

TUTAJ Zamiast używać klauzuli WHERE, musisz użyć POSIADAJĄC ..

bez użycia klauzuli GROUP BY klauzula HAVING działa jak klauzula WHERE

SELECT name  
FROM bonus  
GROUP BY name  
HAVING sum(salary) > 200  

3

Różnica czarno-biała WHEREi HAVINGklauzula:

Główną różnicą między klauzulą WHEREa HAVINGjest to, że WHEREjest używana do operacji na wierszach i HAVINGdo operacji na kolumnach.

Dlaczego potrzebujemy HAVINGklauzuli?

Jak wiemy, funkcje agregujące można wykonywać tylko na kolumnach, więc nie możemy używać funkcji agregujących w WHEREklauzuli. Dlatego używamy funkcji agregujących w HAVINGklauzuli.


1

W zapytaniu zagregowanym (dowolne zapytanie, w którym używana jest funkcja agregująca) Predykaty w klauzuli where są oceniane przed wygenerowaniem zagregowanego pośredniego zestawu wyników,

Predykaty w klauzuli Have są stosowane do zagregowanego zestawu wyników PO wygenerowaniu go. Dlatego warunki predykatów dla wartości zagregowanych muszą być umieszczone w klauzuli Have, a nie w klauzuli Where i dlatego można używać aliasów zdefiniowanych w klauzuli Select w klauzuli Have, ale nie w klauzuli Where.


1

Miałem problem i odkryłem inną różnicę między WHEREi HAVING. Nie działa w ten sam sposób na indeksowane kolumny.

WHERE my_indexed_row = 123 pokaże wiersze i automatycznie wykona „ZAMÓWIENIE ASC” w innych indeksowanych wierszach.

HAVING my_indexed_row = 123 pokazuje wszystko, od najstarszego „wstawionego” wiersza do najnowszego, bez uporządkowania.


Skąd wiesz, że jest to zdefiniowana różnica między dwiema stronami, a nie przypadek wdrożenia określonego serwera SQL, którego używasz?
JdeBP,

Właśnie przetestowałem to na MariaDB. Wydaje mi się, że to serwer SQL, którego używałem 8 lat temu, przyniósł różne wyniki.
Simmoniz

1

Gdy GROUP BYnie jest używany, klauzule WHEREi HAVINGsą zasadniczo równoważne.

Jednak gdy GROUP BYjest używany:

  • WHEREKlauzula służy do ewidencji filtracyjnych od wyniku. Filtrowanie następuje przed utworzeniem jakichkolwiek grupowań.
  • HAVINGKlauzula jest stosowana do wartości filtrów z grupy (tj aby sprawdzić warunki po agregacji do grup została wykonana).

Zasoby stąd


posiadanie i gdzie nie są zasadniczo równoważne. spowoduje błąd podczas wykonywania. jest niepoprawny w klauzuli HAVING, ponieważ nie jest zawarty ani w funkcji agregującej, ani w klauzuli GROUP BY.
Nagendra Kumar

1

Jednym ze sposobów myślenia o tym jest to, że klauzula have jest dodatkowym filtrem do klauzuli where.

WHERE klauzula jest stosowana filtry rekordy od wyniku. Filtr występuje przed utworzeniem jakichkolwiek grupowań. HAVING punkt stosuje się wartości filtrów z grupy


0

Od tutaj .

standard SQL wymaga, aby HAVING odwoływał się tylko do kolumn w klauzuli GROUP BY lub kolumn używanych w funkcjach agregujących

w przeciwieństwie do klauzuli WHERE, która jest stosowana do wierszy bazy danych


Źródło mówi: „Użycie pozycji kolumn jest przestarzałe, ponieważ składnia została usunięta ze standardu SQL”. Niestety, jest to błędne: nic nie jest nigdy usuwane ze Standardu, co jak na ironię wciąż mamy HAVINGdekady po tym, jak zostało „przestarzałe” przez tabele pochodne.
onedaywhen

Nieco pedantyczny, ale cytat jest niepoprawny, np. Rozważ SELECT 1 FROM T HAVING COUNT(*) >= 1;- nie odwołuje się do kolumn w GROUP BYklauzuli (nie ma żadnych) ani do kolumn w funkcjach agregujących (zapytanie nie odwołuje się wcale do kolumn).
onedaywhen

0

Podczas pracy nad projektem było to również moje pytanie. Jak wspomniano powyżej, HAVING sprawdza warunek na już znalezionym wyniku zapytania. Ale GDZIE służy do sprawdzania warunku podczas wykonywania zapytania.

Podam przykład, który to zilustruje. Załóżmy, że masz taką tabelę bazy danych.

usertable {int userid, date datefield, int dailyincome}

Załóżmy, że następujące wiersze znajdują się w tabeli:

1, 2011-05-20, 100

1, 2011-05-21, 50

1, 2011-05-30, 10

2, 2011-05-30, 10

2, 2011-05-20, 20

Teraz chcemy dostać userids i sum(dailyincome)czyjesum(dailyincome)>100

Jeśli napiszemy:

WYBIERZ identyfikator użytkownika, suma (dzienny przychód) Z tabeli użytkownika GDZIE suma (dzienny przychód)> 100 GRUPA WG użytkownika

To będzie błąd. Prawidłowe zapytanie to:

WYBIERZ identyfikator użytkownika, suma (dzienny przychód) Z GRUPY użytkowników Tabela według identyfikatora użytkownika POZIOM suma (dzienny przychód)> 100


0

Klauzula WHERE służy do porównywania wartości w tabeli podstawowej, natomiast klauzula HAVING może być używana do filtrowania wyników funkcji agregujących w zestawie wyników zapytania Kliknij tutaj !


-1

Używam HAVING do ograniczenia zapytania w oparciu o wyniki funkcji agregującej. EG wybierz * w grupie blahblahblah przez COŚ mając liczbę (COŚ)> 0


-1

Może być tak, że tematem „gdzie” jest rząd, podczas gdy tematem „posiadania” jest grupa. Czy mam rację?


3
Musisz być pewien, zanim opublikujesz odpowiedź. Może to być mylące dla innych.
pippin1289
Korzystając z naszej strony potwierdzasz, że przeczytałeś(-aś) i rozumiesz nasze zasady używania plików cookie i zasady ochrony prywatności.
Licensed under cc by-sa 3.0 with attribution required.