2011-08-23 5 views
13

mam to SQL i SQL Server daje mi następujący błąd:kruszywo zapytań SQL nie może pojawić się w klauzuli WHERE

An aggregate may not appear in the WHERE clause unless it is in a subquery contained in a HAVING clause or a select list.

SELECT 
    SUM(M1.InvoiceTotal)-SUM(M1.AmountApplied) as PastDueAmount 
    , M1.BillingID 
    , M2.Name 
    , M2.DelinquentDaysThreshold 
    , M2.DelinquentAmountThreshold 
    , DATEDIFF(d, MIN(BillingDate),GETDATE()) as DaysLate 
FROM Invoices M1 
LEFT JOIN ClientAccounts M2 ON M1.BillingID = M2.ID 
WHERE 
    InvoiceTotal <> AmountApplied 
    AND M2.DelinquentDaysThreshold > DATEDIFF(d, MIN(BillingDate),GETDATE()) 
    OR (SUM(M1.InvoiceTotal)-SUM(M1.AmountApplied)) > M2.DelinquentAmountThreshold 
GROUP BY 
    M1.BillingID 
    , M2.Name 
    , M2.DelinquentDaysThreshold 
    , M2.DelinquentAmountThreshold 

w klauzuli WHERE, chcę tylko, aby wyciągnąć rekordy, w których najstarsza niezapłacona faktura fakturowania Data jest większa niż wartość DelinquentDaysThreshhold (w dniach), lub wartość PastDueAmount (wartość obliczona) jest większa niż wartość DelinquentAmountThreshold.
Z jakiegoś powodu SQL Server nie lubi zagregowanych kwot.

+1

Pamiętaj, aby zapoznać się z FAQ o reputacji i głosowania itp http://meta.stackexchange.com/questions/7237/how-does-reputation-work – gbn

+0

To nie tylko SQL-serwer, który wykluczy przy użyciu agregatów w klauzuli "WHERE", jest to ogólna kwestia SQL, dlatego wprowadzono 'HAVING'. – Johan

Odpowiedz

25

Użyj BIORĄC zgodnie z komunikatem o błędzie, który wymaga GROUP BY

SELECT 
    SUM(M1.InvoiceTotal)-SUM(M1.AmountApplied) as PastDueAmount, 
    M1.BillingID, M2.Name, 
    M2.DelinquentDaysThreshold, M2.DelinquentAmountThreshold, 
    DATEDIFF(d, MIN(BillingDate),GETDATE()) as DaysLate 
FROM 
    Invoices M1 
    LEFT JOIN 
    ClientAccounts M2 ON M1.BillingID = M2.ID 
WHERE 
    InvoiceTotal <> AmountApplied 
    AND 
    M2.DelinquentDaysThreshold > DATEDIFF(d, MIN(BillingDate),GETDATE()) 
GROUP BY 
    M1.BillingID, M2.Name, 
    M2.DelinquentDaysThreshold, M2.DelinquentAmountThreshold, 
    DATEDIFF(d, MIN(BillingDate),GETDATE()) 
HAVING 
    (SUM(M1.InvoiceTotal)-SUM(M1.AmountApplied)) > M2.DelinquentAmountThreshold 
0

In the where clause, I only want to pull records where the oldest unpaid Billing Invoice Date is greater than the DelinquentDaysThreshhold (in days)

niektóre zagadnienia wydajności z klauzuli HAVING:

When you use GROUP BY with the HAVING clause, the GROUP BY clause divides the rows into sets of grouped rows and aggregates their values, andthen the HAVING clause eliminates undesired aggregated groups. In many cases,you can write your select statement so it will contain only WHERE and GROUP BY clauses without a HAVING clause.

Jako alternatywę do klauzuli HAVING można również użyć tabel pochodnych do s Ølve ten problem:

SELECT t1.SomeID, t1.SomeThreshold, totals.NumericTotal 
FROM Table1 t1 
     INNER JOIN (
      SELECT SomeID, SUM(SomeNumericValue) NumericTotal 
      FROM Table1 
      Group By SomeID 
     ) totals 
      ON t1.SomeID = totals.SomeID 
WHERE totals.NumericTotal > t1.SomeThreshold 
+2

Skąd ta ogólna odpowiedź, która nie pasuje do pytania OP, została skopiowana/wklejona? – gbn

+1

@ gbn: Przepraszam? OP zapytał, w jaki sposób użyć aggagowanej sumy w klauzuli where. To pozwala to osiągnąć. Nie musisz być niegrzeczny, koleś. –

+2

Używałbyś wtedy HAVING, a nie wyprowadzonej tabeli. W związku z tym sformułuję: dlaczego poświęciłeś czas na pisanie tego fragmentu, a nie na oryginalnym zapytaniu OP? – gbn