2010-06-22 9 views
6

Próbuję utworzyć tabelę wyników z ostatnią ukończoną datą kursu dla każdego kodu kursu, a także ostatni ukończony kod kursu dla każdego pracownika łącznie . Poniżej jest moje zapytanie:MAX() i MAX() NAD PARTYCJI PRZEZ generuje błąd 3504 w zapytaniu Teradata

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 

Ta kwerenda produkuje następujący błąd:

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

Jeśli usunąć MAX() OVER (partycję ...) linii, zapytanie wykonuje dobrze, więc Wyizolowałem problem z tą linią, ale po przeszukiwaniu tych forów i internetu nie widzę, co robię źle. Czy ktoś może pomóc?

+0

Ponieważ używasz OVER w odniesieniu do maksimum, SQL widzi te jako funkcje analityczne - nie agregaty. –

Odpowiedz

4

Jak wspomina Kucyk w komentarzu, nie można łączyć funkcji OLAP z funkcjami zagregowanymi.

Być może łatwiej jest uzyskać datę ostatniego zakończenia dla każdego pracownika i dołączyć do zestawu danych zawierającego datę ostatniego zakończenia każdego z trzech wybranych kursów.

To niesprawdzone pomysł, który powinien nadzieją umieścić cię na właściwą drogę:

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

wiem, że to jest bardzo stare pytanie, ale już został poproszony przez kogoś innego coś podobnego.

Nie mam TeraData, ale czy nie możesz wykonać następujących czynności?

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 

Teraz GROUP BY zapewnia jeden wiersz na kurs na pracownika. Oznacza to, że potrzebujesz tylko prostej MAX(), aby uzyskać max_course_date.

przed twoimi GROUP BY właśnie dając jeden wiersz na pracownika, a MAX() OVER() starał się dać wiele wyników dla tego jednego wiersza (jeden za oczywiście).

Zamiast tego potrzebujesz teraz klauzuli OVER(), aby uzyskać MAX() dla pracownika jako całości. Jest to teraz uzasadnione, ponieważ każdy pojedynczy wiersz otrzymuje tylko jedną odpowiedź (ponieważ pochodzi z super-zestawu, a nie z podzbioru). Z tego samego powodu klauzula OVER() odnosi się teraz do poprawnej wartości skalarnej, zdefiniowanej w klauzuli GROUP BY; employee_number.


Może krótka droga mówiąc byłoby to, że aggregate z klauzulą ​​OVER() musi być super-set z GROUP BY, a nie sub-set.

Utwórz zapytanie z numerem GROUP BY na poziomie odpowiadającym wybranym wierszom, a następnie określ klauzule OVER(), jeśli chcesz agregować na wyższym poziomie.

+0

Spowoduje to również wygenerowanie tego samego komunikatu o błędzie. Logiczne funkcje OLAP są obliczane ** po ** GRUPIE bY/HAVING, dzięki czemu można uzyskać dostęp do kolumn w GROUP BY lub kolumnach z funkcją agregującą. Poniżej wygląda dziwnie, ale jest Standardowy SQL: ** MAX (MAX (course_completion_date)) PONAD (PARTION BY employee_number) ** A ponieważ Teradata pozwala na ponowne użycie aliasu działa to również: ** MAX (max_course_date) OVER (PARTITION BY employee_number) ** – dnoeth

1

Funkcje logiczne OLAP są obliczane po GROUP BY/HAVING, dzięki czemu można uzyskać dostęp do kolumn GROUP BY lub kolumn z funkcją agregującą.W następstwie wygląda dziwnie, ale jest standardem SQL:

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 

I jak Teradata umożliwia ponowne wykorzystanie aliasu Działa to również:

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

Powiedziałeś, że ** olap ** funkcje są obliczane po ** grupie przez/mając **, ale w tobie powyżej kodu używasz 'course_code' w klauzuli partycji, która nie jest częścią * * klauzula group by **. Powyższy kod nie działa w Oracle. Błąd to "ORA-00979: nie wyrażenie GROUP BY" – frank

+0

@frank: Prawidłowo, 'course_code' musi być dodane do' GROUP BY' – dnoeth

+0

dzięki za potwierdzenie. Nowe funkcje analityczne nie były pewne, czy miałem rację. – frank