MAX()和MAX()OVER PARTITION BY在Teradata Query中产生错误3504

时间:2010-06-22 19:43:25

标签: sql aggregate-functions teradata database-partitioning

我正在尝试生成一个结果表,其中包含每个课程代码的最后完成课程日期,以及每位员工最后完成的课程代码。以下是我的询问:

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

此查询产生以下错误:

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

如果我删除MAX()OVER(PARTITION BY ...)行,查询执行得很好,所以我已将问题隔离到该行,但在搜索这些论坛和互联网后我看不到我做错了什么。有人可以帮忙吗?

5 个答案:

答案 0 :(得分:5)

正如Ponies在评论中所说,你不能将OLAP函数与聚合函数混合使用。

也许更容易获得每个员工的最后完成日期,并将其加入到包含三个目标课程中每个目标课程的最后完成日期的数据集中。

这是一个未经考验的想法,希望能让你走上正确的道路:

  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 :(得分:1)

我知道这是一个非常古老的问题,但我被别人问过类似的问题。

我没有TeraData,但你不能做以下事情吗?

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

GROUP BY现在确保每位员工每门课程一行。这意味着您只需要一个MAX()来获得max_course_date

GROUP BY为每位员工提供一行之前,MAX() OVER()试图为该行(每个课程一个)提供多个结果

相反,您现在需要OVER()子句来获取整个员工的MAX()。这现在是合法的,因为每个单独的行只得到一个答案(因为它来自超集,而不是子集)。此外,出于同样的原因,OVER()子句现在引用有效的标量值,由GROUP BY子句定义; employee_number


这可能只是一个简短的说法,即带有aggregate子句的OVER()必须是GROUP BY的超集,而不是子集。

在代表所需行的级别使用GROUP BY创建查询,如果要在更高级别聚合,请指定OVER()子句。

答案 2 :(得分:1)

逻辑上OLAP函数是在GROUP BY / HAVING之后计算的,因此您只能访问GROUP BY中的列或具有聚合函数的列。以下看起来很奇怪,但是标准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

由于Teradata允许重新使用别名,这也有效:

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

答案 3 :(得分:0)

我认为即使在很久以前,这仍然会奏效。

SELECT employee_number, Row_Number()  
   OVER (PARTITION BY course_code ORDER BY course_completion_date DESC ) as rownum
FROM employee_course_completion
WHERE course_code IN ('M910303', 'M91301R', 'M91301P')
   AND rownum = 1

如果您要获取日期相同的最后一个ID,则可以假定主键为ID来使用。

SELECT employee_number, Row_Number()  
   OVER (PARTITION BY course_code ORDER BY course_completion_date DESC, Id Desc) as rownum    FROM employee_course_completion
WHERE course_code IN ('M910303', 'M91301R', 'M91301P')
   AND rownum = 1

答案 4 :(得分:-1)

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