0

是否可以从 WHERE 子句的子查询中引用“FROM”子句中定义的内联视图?

SELECT tmp.TeacherName,
       tmp.courseid,
       tmp.AvgAttendingStudents
FROM   (SELECT T.TeacherID              AS ID,
               T.TeacherName            AS Name,
               C.CourseID               AS CourseID,
               avg(L.AttendingStudents) AS AvgAttendingStudents
        FROM   Teachers AS T
               join Courses AS C
                 ON C.TeacherID = T.TeacherID
               join Lessons AS L
                 ON L.CourseID = C.CourseID
        GROUP  BY T.TeacherID,
                  C.CourseID) AS tmp
WHERE  tmp.AvgAttendingStudents = (SELECT max(AvgAttendingStudents)
                                   FROM   tmp AS tmp2
                                   WHERE  tmp2.TeacherID = tmp.TeacherID);  

在这个例子中,我试图列出所有的老师,对于他们每个人,我想展示具有最高平均参加学生的课程(根据所有课程计算)。我尝试使用内联视图 (tmp) 来计算每门课程的平均参加学生人数,但我不知道是否可以在子查询 SELECT max(...) 中引用该视图。我需要它来使用 Oracle,但不幸的是,目前我没有任何 Oracle 数据库可以尝试。我尝试使用 MySQL(因为我认为我没有使用任何特定于 Oracle 的功能),但正如预期的那样,我收到错误“表 'db.tmp' 不存在”。甲骨文有可能吗?

这是我的示例架构:

CREATE TABLE Courses
  (
     CourseID   INTEGER PRIMARY KEY,
     CourseName VARCHAR(32),
     TeacherID  INTEGER
  );

CREATE TABLE Teachers
  (
     TeacherID   INTEGER PRIMARY KEY,
     TeacherName VARCHAR(32)
  );

CREATE TABLE Lessons
  (
     LessonDate        TIMESTAMP,
     CourseID          INTEGER,
     AttendingStudents INTEGER,
     PRIMARY KEY (LessonDate, CourseID)
  );  

(对不起,我的英语不好)

4

2 回答 2

0

您可以使用 having 子句,它可以为您提供一种约束聚合函数的方法。

这里有一个例子:

    SELECT T.TeacherID              AS ID,
           T.TeacherName            AS Name,
           C.CourseID               AS CourseID,
           avg(L.AttendingStudents) AS AvgAttendingStudents
    FROM   Teachers AS T
           join Courses AS C
             ON C.TeacherID = T.TeacherID
           join Lessons AS L
             ON L.CourseID = C.CourseID
    GROUP  BY T.TeacherID,
              T.TeacherName
              C.CoursesID
    HAVING  avg(L.AttendingStudents) = (SELECT max(AvgAttendingStudents)
                               FROM   Teachers AS tmp2
                               WHERE  tmp2.TeacherID = T.TeacherID);

我只是删除了您的第一个嵌套查询并将 AvgAttendingStudents 更改为 avg(L.AttendingStudents) (因为您不能在 Have 子句中使用变量)并在 Group 子句中添加选定的属性,我不测试但这里的方法是诡计。

不要忘记添加在组子句中选择的未聚合 var。

这里有一个关于有条款的文档。

于 2016-05-07T09:04:01.647 回答
0

您是对的,因为您不能以这种方式引用派生表(“内联视图”)。您需要将派生表(“内联视图”)重写为公用表表达式:

您还有其他错误。在派生表中,您重命名TeacherIDIDTeacherNameName因此您需要使用这些列名而不是“真实”列名。

此外,Oracle 不支持AS表别名,因此您也需要摆脱这些别名。

因此,该语句的直接重写将是:

with tmp as (
  SELECT T.TeacherID              AS ID,
         T.TeacherName            AS Name,
         C.CourseID               AS CourseID,
         avg(L.AttendingStudents) AS AvgAttendingStudents
  FROM   Teachers T
         join Courses C
           ON C.TeacherID = T.TeacherID
         join Lessons L
           ON L.CourseID = C.CourseID
  GROUP  BY T.TeacherID,
            C.CourseID
)
SELECT tmp.name,
       tmp.courseid,
       tmp.AvgAttendingStudents
FROM tmp
where tmp.AvgAttendingStudents = (SELECT max(AvgAttendingStudents)
                                  FROM   tmp tmp2
                                  WHERE  tmp2.id = tmp.id);

但是,由于和聚合函数的无效使用,上述方法在 Oracle 中不起作用。group by以上将导致“ORA-00979:不是 GROUP BY 表达式”,请参阅此SQLFiddle

为此,您需要在 CTE 中使用窗口函数并摆脱group by

with tmp as (
  SELECT T.TeacherID              AS ID,
         T.TeacherName            AS Name,
         C.CourseID               AS CourseID,
         avg(L.AttendingStudents) over (partition by t.teacherid, c.courseid) AS avgattendingstudents 
  FROM   Teachers T
         join Courses C
           ON C.TeacherID = T.TeacherID
         join Lessons L
           ON L.CourseID = C.CourseID
)
SELECT tmp.name,
       tmp.courseid,
       tmp.AvgAttendingStudents
FROM tmp
where tmp.AvgAttendingStudents = (SELECT max(AvgAttendingStudents)
                                  FROM   tmp tmp2
                                  WHERE  tmp2.id = tmp.id);

有关示例,请参阅此SQLFiddle


请注意,您不能使用 MySQL 测试上述查询,因为它不支持现代 SQL,如公用表表达式或窗口函数。

但是您可以使用 SQLFiddle 示例用数据对其进行测试。

于 2016-05-07T09:13:50.310 回答