Aggregatfunktion in SQL WHERE-Klausel

72

Bei einem Test an der Universität gab es eine Frage; Ist es möglich, eine Aggregatfunktion in der SQL WHEREKlausel zu verwenden ?

Ich habe immer gedacht, dass dies nicht möglich ist und ich kann auch kein Beispiel finden, wie es möglich wäre. Aber meine Antwort wurde als falsch markiert und jetzt möchte ich wissen, in welchen Fällen es möglich ist, eine Aggregatfunktion in der zu verwenden WHERE. Auch wenn es nicht möglich ist, wäre es schön, einen Link zu der Spezifikation zu bekommen, in der es beschrieben wird.

n3on
quelle

Antworten:

31

Sie haben das DBMS nicht erwähnt. Angenommen, Sie verwenden MS SQL-Server, habe ich eine selbsterklärende T-SQL-Fehlermeldung gefunden:

"Ein Aggregat wird möglicherweise nicht in der WHERE-Klausel angezeigt, es sei denn, es befindet sich in einer Unterabfrage, die in einer HAVING-Klausel oder einer Auswahlliste enthalten ist, und die zu aggregierende Spalte ist eine äußere Referenz."

http://www.sql-server-performance.com/


Und ein Beispiel, dass es in einer Unterabfrage möglich ist.

Alle Kunden und kleinste Bestellung für diejenigen anzeigen, die 5 oder mehr Bestellungen haben (und NULL für andere):

SELECT a.lastname
     , a.firstname
     , ( SELECT MIN( o.amount )
         FROM orders o
         WHERE a.customerid = o.customerid
           AND COUNT( a.customerid ) >= 5
        )
        AS smallestOrderAmount
FROM account a
GROUP BY a.customerid
       , a.lastname
       , a.firstname ;

AKTUALISIEREN.

Das obige läuft sowohl in SQL-Server als auch in MySQL, gibt aber nicht das erwartete Ergebnis zurück. Der nächste ist näher. Ich denke, es hat damit zu tun, dass das Feld customeridGROUPed BY, das im Abfrage-Unterabfrage-Join verwendet wird, im ersten Fall PRIMARY KEY der äußeren Tabelle ist und im zweiten Fall nicht.

Alle Kunden-IDs und Anzahl der Bestellungen für diejenigen anzeigen, die 5 oder mehr Bestellungen haben (und NULL für andere):

SELECT o.customerid
     , ( SELECT COUNT( o.customerid )
         FROM account a
         WHERE a.customerid = o.customerid
           AND COUNT( o.customerid ) >= 5
        )
        AS cnt
FROM orders o
GROUP BY o.customerid ;
Tim Schmelter
quelle
1
Ja, ich habe kein DBMS erwähnt, da kein DBMS angegeben ist. Es heißt nur SQL -_-
n3 am
1
Ich denke, diese Möglichkeit wurde in den SQL-92-Spezifikationen hinzugefügt. Keine Ahnung, wann verschiedene Produkte die Funktionalität hinzugefügt haben. Das Testen nur mit MySQL und SQL-Server zeigt ein etwas anderes Verhalten (SQL-Server ist strenger und wahrscheinlich näher an den Spezifikationen). Es wäre interessant, wenn jemand anderes nach anderen SQL-Implementierungen suchen könnte.
Ypercubeᵀᴹ
Während Puristen werden nicht zustimmen, die meisten Orte , an denen ich gearbeitet habe sagen SQL haben Microsoft SSMS bedeuten, mit TSQL
JosephDoggie
111

HAVING ist wie WHERE mit Aggregatfunktionen, oder Sie könnten eine Unterabfrage verwenden.

select EmployeeId, sum(amount)
from Sales
group by Employee
having sum(amount) > 20000

Oder

select EmployeeId, sum(amount)
from Sales
group by Employee
where EmployeeId in (
    select max(EmployeeId) from Employees)
Jason Goemaat
quelle
3
Ja, dass es möglich ist, wenn ich es weiß. Aber das WO wurde gegeben. Ich denke, es ist eine Definitionssache.
n3on
1
Vielen Dank! Genau das, was ich wissen und verstehen musste. Up Abstimmung.
Lukas
1
Danke, ich wollte meine Anfrage in der Aufgabe belassen und dann finde ich diese ... Ihre Antwort hilft mir wirklich
als Bhullar
1
Danke, das hat mir viel Zeit gespart, alle anderen Quellen da draußen haben nicht die Einfachheit gegeben, die Sie getan haben. Perfekte Antwort.
Jeff
12

Sie können ein Aggregat nicht direkt in einer WHERE-Klausel verwenden. Dafür gibt es HAVING-Klauseln.

Sie können eine Unterabfrage verwenden, die ein Aggregat in der WHERE-Klausel enthält.

Jonathan Leffler
quelle
1
Ich weiß, dass es als Unterabfrage möglich ist, aber ich bin mir nicht sicher, ob ich dann sagen kann, dass ich eine Aggregatfunktion in WHERE verwenden kann ... ich denke, es ist eine Definitionssache.
n3on
1
@ n3on: Ich stimme zu ... Ich würde argumentieren, dass es nicht möglich ist, Aggregate direkt in einer WHERE-Klausel zu verwenden - wie gesagt. Es ist nur möglich, sie als Teil einer Unterabfrage zu verwenden - und das würde in meinem Buch nicht als "in einer WHERE-Klausel" gelten. Wenn Sie die vorsichtige, nuancierte Antwort geben, sehe ich nicht, wie sie Ihnen etwas vorwerfen können. Wenn es sich um eine Multi-Choice-Frage handelt, stecken Sie fast fest.
Jonathan Leffler
2
Siehe Tims Antwort. Es ist möglich.
Ypercubeᵀᴹ
10

AKTUALISIERTE Abfrage:

select id from t where id < (select max(id) from t);

Es werden alle bis auf die letzte Zeile aus der Tabelle t ausgewählt.

Chandranshu
quelle
2
Ich glaube, das wird vom DBMS abhängen, wie Tim sagte. In Standard-SQL müssen Sie es schreiben alsSELECT id FROM t WHERE id < (SELECT MAX(id) FROM t)
Coding District
1
Ja, du hast recht. Ich erinnerte mich nur daran, dass es aus meinen frühen Datenbank-Tutorials möglich war, in denen wir die obersten 5 Zeilen auswählen mussten, ohne TOP oder LIMIT oder ROWNUM zu verwenden.
Chandranshu
2
Ja, aber dann befindet sich die Aggregatfunktion in der select-Klausel der Unterabfrage und nicht im WHERE. Und ich denke, eine Unterabfrage kann nicht als Aggregatfunktion angesehen werden.
n3on
3

Eine andere Lösung besteht darin, die Aggregatfunktion in die benutzerdefinierte Skalarfunktion zu verschieben

Erstellen Sie Ihre Funktion:

CREATE FUNCTION getTotalSalesByProduct(@ProductName VARCHAR(500))
RETURNS INT
AS
BEGIN

DECLARE @TotalAmount INT

SET @TotalAmount = (select SUM(SaleAmount) FROM Sales where Product=@ProductName)

RETURN @TotalAmount

END

Verwenden Sie die Funktion in der Where-Klausel

SELECT ProductName, SUM(SaleAmount) AS TotalSales
FROM Sales
WHERE dbo.getTotalSalesByProduct(ProductName)  > 1000
GROUP BY Product

Verweise:

1. 2.

Hoffnung hilft jemandem.

Shaijut
quelle