0

"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 固有の機能を使用しているとは思わないため) が、予想どおり、「テーブル '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)
  );  

(下手な英語でごめんなさい)

4

2 に答える 2

0

そのように派生テーブル(「インラインビュー」)を参照できないという点で、あなたは正しいです。派生テーブル (「インライン ビュー」) を共通テーブル式に書き換える必要があります。

そこには他のエラーもあります。派生テーブルでは、名前TeacherIDIDおよびTeacherNameに変更するNameため、「実際の」列名ではなく、これらの列名を使用する必要があります。

また、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);

ただし、and 集計関数の使用が無効なため、上記は 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を参照してください。


一般的なテーブル式やウィンドウ関数などの最新の SQLをサポートしていないため、MySQL で上記のクエリをテストできないことに注意してください。

ただし、SQLFiddle の例を使用して、データでテストできます。

于 2016-05-07T09:13:50.310 に答える
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) に変更し (Having 句で変数を操作できないため)、選択した属性を Group 句に追加します。テストはしませんが、ここでは騙す。

group 句で選択した集計されていない var を追加することを忘れないでください。

ここでは、節を持っていることに関するドキュメントです。

于 2016-05-07T09:04:01.647 に答える