2011-08-23 1 views
13

Ho questa istruzione SQL e SQL Server mi sta dando il seguente errore:SQL query di aggregazione potrebbe non apparire nella clausola 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 

nella clausola WHERE, voglio solo tirare record in cui il la data di fattura di fatturazione non pagata più vecchia è maggiore del valore DelinquentDaysThreshhold (in giorni), oppure il valore PastDueAmount (un valore calcolato) è maggiore di DelinquentAmountThreshold.
Per qualche motivo a SQL Server non piacciono gli importi aggregati.

+1

Ricordati di leggere le FAQ sulla reputazione e il voto ecc http://meta.stackexchange.com/questions/7237/how-does-reputation-work – gbn

+0

Non solo SQL-server che esclude dal finanziamento usando gli aggregati nella clausola 'WHERE', questa è una cosa SQL generale, ecco perché è stato introdotto' HAVING'. – Johan

risposta

25

Utilizzare la VISTA come per il messaggio di errore, che richiede un 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)

Alcune considerazioni sulle prestazioni con la clausola 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.

In alternativa alla clausola HAVING, è anche possibile utilizzare le tabelle derivate Olve questo problema:

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

Dove hai copiato/incollato questa risposta generica che non corrisponde alla domanda dell'OP? – gbn

+1

@gbn: Mi scusi? L'OP ha chiesto come utilizzare un totale aggragato nella clausola where. Questo lo realizza. Non c'è bisogno di essere scortese, amico. –

+2

Quindi useresti HAVING, non una tabella derivata. Quindi riformulerò: perché hai passato del tempo a scrivere questo frammento piuttosto che usare la query originale di OP? – gbn