2010-06-22 7 views
6

Sto provando a produrre una tabella dei risultati con l'ultima data del corso completa per ogni codice del corso, nonché l'ultimo codice del corso completo per ogni dipendente . Qui di seguito è la mia domanda:MAX() e MAX() OVER PARTITION BY genera l'errore 3504 in Teradata Query

SELECT employee_number, 
     MAX(course_completion_date) 
      OVER (PARTITION BY course_code) AS max_course_date, 
     MAX(course_completion_date) AS max_date 
FROM employee_course_completion 
WHERE course_code IN ('M910303', 'M91301R', 'M91301P') 
GROUP BY employee_number 

Questa interrogazione produce il seguente errore:

3504 : Selected non-aggregate values must be part of the associated group 

Se rimuovo il MAX() OVER (partizione DA ...) la linea, la query esegue bene, in modo da Ho isolato il problema su questa linea, ma dopo aver cercato questi forum e Internet non riesco a vedere cosa sto facendo male. Qualcuno può aiutare?

+0

perché si sta utilizzando oltre con riferimento al MAX, SQL vede queste come funzioni analitiche - non aggregati. –

risposta

4

Come dice Ponies in un commento, non è possibile combinare funzioni OLAP con funzioni di aggregazione.

Forse è più semplice ottenere l'ultima data di completamento per ciascun dipendente e aggiungerla a un set di dati contenente l'ultima data di completamento per ciascuno dei tre corsi mirati.

Questa è un'idea non testata che dovrebbe auspicabilmente, si mette giù la strada giusta:

SELECT employee_number, 
     course_code, 
     MAX(course_completion_date) AS max_date, 
     lcc.LAST_COURSE_COMPLETED 
    FROM employee_course_completion ecc 
     LEFT JOIN (
      SELECT employee_number, 
        MAX(course_completion_date) AS LAST_COURSE_COMPLETED 
       FROM employee_course_completion 
       WHERE course_code IN ('M910303', 'M91301R', 'M91301P') 
     ) lcc 
     ON lcc.employee_number = ecc.employee_number 
    WHERE course_code IN ('M910303', 'M91301R', 'M91301P') 
GROUP BY employee_number, course_code, lcc.LAST_COURSE_COMPLETED 
1

So che questa è una domanda molto vecchio, ma mi è stato chiesto da qualcun altro qualcosa di simile.

Non ho TeraData, ma non si può fare quanto segue?

SELECT employee_number, 
     course_code, 
     MAX(course_completion_date)          AS max_course_date, 
     MAX(course_completion_date) OVER (PARTITION BY employee_number) AS max_date 
FROM employee_course_completion 
WHERE course_code IN ('M910303', 'M91301R', 'M91301P') 
GROUP BY employee_number, course_code 

Il GROUP BY ora assicura una riga per corso per dipendente. Ciò significa che è sufficiente una scala MAX() per ottenere lo max_course_date.

Prima che il GROUP BY era solo dando una riga per dipendente, e la MAX() OVER() stava cercando di dare più risultati per che una riga (uno per ogni corso).

Invece, ora è necessario il OVER() clausola per ottenere il MAX() per l'impiegato nel suo complesso. Questo è ora legittimo perché ogni singola riga ottiene una sola risposta (poiché deriva da un super-set, non da un sottoinsieme). Inoltre, per lo stesso motivo, la clausola OVER() fa ora riferimento a un valore scalare valido, come definito dalla clausola GROUP BY; employee_number.


Forse un breve modo di dire questo sarebbe che un aggregate con una clausola OVER() deve essere un super-set del GROUP BY, non è un sottoinsieme.

Creare la query con un GROUP BY al livello che rappresenta le righe desiderate, quindi specificare le clausole OVER() se si desidera aggregare a un livello superiore.

+0

Ciò produrrà anche lo stesso messaggio di errore. Logicamente le funzioni OLAP vengono calcolate ** dopo ** GROUP bY/HAVING, quindi è possibile accedere solo alle colonne in GROUP BY o alle colonne con una funzione di aggregazione. Di seguito sembra strano, ma è SQL standard: ** MAX (MAX (course_completion_date)) OVER (PARTITION BY employee_number) ** E poiché Teradata consente di riutilizzare un alias, funziona anche: ** MAX (max_course_date) OVER (PARTITION BY numero_dipendente) ** – dnoeth

1

Logicamente le funzioni OLAP vengono calcolate dopo GROUP BY/HAVING, quindi è possibile accedere solo alle colonne in GROUP BY o alle colonne con una funzione di aggregazione.In seguito sembra strano, ma è SQL standard:

SELECT employee_number, 
     MAX(MAX(course_completion_date)) 
      OVER (PARTITION BY course_code) AS max_course_date, 
     MAX(course_completion_date) AS max_date 
FROM employee_course_completion 
WHERE course_code IN ('M910303', 'M91301R', 'M91301P') 
GROUP BY employee_number, course_code 

E come Teradata permette di ri-utilizzando un alias questo funziona anche:

SELECT employee_number, 
     MAX(max_date) 
      OVER (PARTITION BY course_code) AS max_course_date, 
     MAX(course_completion_date) AS max_date 
FROM employee_course_completion 
WHERE course_code IN ('M910303', 'M91301R', 'M91301P') 
GROUP BY employee_number, course_code 
+0

Hai affermato che le funzioni di ** olap ** vengono calcolate dopo ** group by/having **, ma nel tuo codice sopra stai usando il codice_ course_ nella clausola partition, che non fa parte del * * gruppo per ** clausola. Il codice sopra non funziona in Oracle. L'errore è 'ORA-00979: non un'espressione GROUP BY' – frank

+0

@frank: corretto, 'course_code' deve essere aggiunto a' GROUP BY' – dnoeth

+0

grazie per la conferma. Nuove funzioni analitiche non erano sicure se avessi ragione. – frank