SQL 内联视图子查询

SQL inline view subquery

是否可以从 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 的功能),但正如预期的那样,我得到了错误 "Table 'db.tmp' doesn't exist"。 这对 Oracle 来说有可能吗?

这是我的示例架构:

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)
  );  

(抱歉我的英语不好)

您可以使用 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)(因为您不能在 Having 子句上使用变量)并在 Group 子句中添加选定的属性,我没有测试但这是解决问题的方法。

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

这里是关于 having clause 的文档。

你是对的,因为你不能那样引用派生的 table ("inline view")。您需要将派生的 table ("inline view") 重写为常见的 table 表达式:

你那里还有其他错误。在派生的 table 中,您将 TeacherID 重命名为 ID,将 TeacherName 重命名为 Name,因此您需要使用这些列名称而不是 "real"。

此外,Oracle 不支持 AS 作为 table 别名,因此您也需要删除这些别名。

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

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);

但是,由于 group by 和聚合函数的无效使用,上述内容 不会 在 Oracle 中工作。以上会导致"ORA-00979: not a GROUP BY expression",看这个SQLFiddle

为此,您需要在 CTE 中使用 window 函数并删除 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 测试上述查询,因为它不支持 modern SQL,如常见的 table 表达式或 window 函数。

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