SQL内联视图子查询

时间:2016-05-07 08:58:12

标签: sql oracle subquery inline-view

是否可以引用" FROM"中定义的内联视图?来自WHERE子句中的子查询的子句?

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'不存在"。 这对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)
  );  

(抱歉我的英语不好)

2 个答案:

答案 0 :(得分:0)

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

这是一个例子:

    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子句中添加选定的attributs,我不测试但是这里的方式做的伎俩。

不要忘记添加在group子句中选择的未经过聚集的var。

这是关于having clause的文档。

答案 1 :(得分:0)

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

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

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

但是,由于group by和聚合函数的使用无效,以上在Oracle中有效。以上结果将导致" 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测试上述查询,因为它不支持常见表表达式或窗口函数等modern SQL

但您可以使用SQLFiddle示例来测试数据。