Common Table Expressions(略してCTE)は、INSERT、SELECT、UPDATE、またはDELETEステートメント内で参照できるレコードの一時的なセットを作成するための単なる手法です。
一般的なテーブル式は、MicrosoftによってSQL Server 2005で導入されました。それらの有効期間はクエリの実行時間と等しいため、データベースメモリにオブジェクトとして保存されません。クエリが完了するとすぐに、データベースメモリから削除されます。 CTEはクエリで何度でも参照でき、自己参照することもできます。
学生テーブルを使用してデータベースを作成し、その中にダミーの学生レコードを挿入してみましょう。このデータベースを使用して、CTEクエリを記述します。いつものように、新しいコードを試す前に、十分にバックアップされていることを確認してください。よくわからない場合は、SQLバックアップに関するこの記事を参照してください。
サーバーで次のクエリを実行します。
CREATE DATABASE schooldb CREATE TABLE student ( id INT PRIMARY KEY, name VARCHAR(50) NOT NULL, gender VARCHAR(50) NOT NULL, DOB datetime NOT NULL, total_score INT NOT NULL, ) INSERT INTO student VALUES (1, 'Jolly', 'Female', '12-JUN-1989', 500), (2, 'Jon', 'Male', '02-FEB-1974', 545), (3, 'Sara', 'Female', '07-MAR-1988', 600), (4, 'Laura', 'Female', '22-DEC-1981', 400), (5, 'Alan', 'Male', '29-JUL-1993', 500), (6, 'Kate', 'Female', '03-JAN-1985', 500), (7, 'Joseph', 'Male', '09-APR-1982', 643), (8, 'Mice', 'Male', '16-AUG-1974', 543), (9, 'Wise', 'Male', '11-NOV-1987', 499), (10, 'Elis', 'Female', '28-OCT-1990', 400);
それでは、非常に単純な共通テーブル式を作成しましょう。このCTEには、1985年1月1日より前に生まれたすべての学生の記録が含まれます。次のスクリプトを参照してください。
USE schooldb; WITH OldStudents AS ( SELECT * FROM student WHERE DOB < '1985-01-01' )
CTEを作成するには、「WITH」キーワードで始まり、その後にCTEの名前と「AS」キーワードが続く必要があります。
次に、括弧内に、CTEが一時的に保存するレコードを返すクエリを作成する必要があります。上記のスクリプトでは、「OldStudents」という名前のCTEを作成しました。
ただし、上記のクエリを実行しようとすると、エラーが発生することに注意してください。これは、CTEを作成したら、すぐに使用する必要があるためです。
新しく作成した「OldStudents」CTEからすべてのレコードを選択しましょう。サーバーで次のスクリプトを試してください。
USE schooldb; WITH OldStudents AS ( SELECT * FROM student WHERE DOB < '1985-01-01' ) SELECT * FROM OldStudents
上記のスクリプトは、次のレコードのセットを取得します。
CTEによる集計の計算
テーブルと同様に、CTEで集計関数を実行できます。 CTEの別の例を見てみましょう。
USE schooldb; WITH SumofScores AS ( SELECT gender, SUM(total_score) as SumScore FROM student GROUP BY gender ) SELECT AVG (SumScore) FROM SumofScores
上記の例では、SumofScoresという名前のCTEを作成しました。このCTEには、studentテーブルのtotal_score列に格納されている値の合計が含まれます。結果は性別の列でグループ化されます。 CTEによって保存されたデータは、メモリに次のように表示されます。
次に、CTEの「SumScore」列でAVG関数を実行しました。スクリプトの最終結果は、2400と2730の平均、つまり2565になります。
これは前の例よりも少し複雑ですが、CTEの概念をより明確に示しています。
CTEでの列のラベル付け
前の例では、CTEの2番目の列にエイリアスを追加しました。名前を「SumScore」に変更しました。これは、CTEで列にラベルを付ける1つの方法であり、テーブルの列エイリアスに似ています。
ただし、CTEで列名を定義する別の方法があります。次のクエリを見てください。
USE schooldb; WITH SumofScores(Gender, SumScore) AS ( SELECT gender, SUM(total_score) FROM student GROUP BY gender ) SELECT AVG (SumScore) From SumofScores
このスクリプトでは、CTE名の後の括弧内に「SumofScores」CTEの列名を追加しました。各列名はコンマで区切られます。
CTEの後のSELECTステートメントを見ると、CTE名の後の括弧内に作成した「SumScore」列を参照していることがわかります。
複数のCTEの作成
これまでのすべての例では、わかりやすくするために1つの共通テーブル式のみを使用しています。 CTEのリストを同時に作成し、それらすべてを組み合わせて最終結果セットで使用できます。
これは、例を使用して最もよく説明されます。以下のスクリプトをご覧ください。
ここでは、2つのCTEを作成します。最初のCTEには、1985年1月1日より前に生まれた学生のすべての記録が保存されます。2番目のCTEには、1985年1月1日以降に生まれた学生のすべての記録が含まれます。
その後、selectステートメントを使用して、両方のCTEからすべてのレコードを取得します。取得されたレコードは、UNIONステートメントを使用してマージされます。最後に、マージされたレコードは、生年月日の昇順で並べ替えられます。
USE schooldb; WITH OldStudents AS ( SELECT * FROM student WHERE DOB < '1985-01-01' ), YoungStudents AS ( SELECT * FROM student WHERE DOB >= '1985-01-01' ) (SELECT * FROM OldStudents UNION SELECT * FROM YoungStudents) ORDER BY DOB
上記のSQLクエリでは、「OldStudents」と「YoungStudents」の2つのCTEを作成しました。すべてのCTEで「WITH」キーワードを使用する必要はないことを言及する価値があります。スクリプトの最初のCTEの前にのみ使用する必要があります。その後は、カンマで区切って任意の数のCTEを作成できます。
上記のスクリプトは、次の結果を取得します。