1. 共同質問
結合クエリはマルチテーブルクエリとも呼ばれ、基本的な実行プロセスはデカルト積です。
1.1 デカルト積を理解する
では、デカルト積とは何でしょうか?
回答: デカルト積は、計算のために 2 つのテーブルを結合し、最初のテーブルの各行を取り出し、それを 2 番目のテーブルの各行と接続して新しい行を取得することです。
デカルト積の例:
学生情報テーブルとクラス情報テーブルという 2 つのテーブルがあるとします。
ここで、これら 2 つのテーブルに対してデカルト積演算を実行します。
デカルト積は乗算演算に相当し、列数は 2 つのテーブルの列の合計であり、行数は 2 つのテーブルの行の積です。
注: デカルト積の実行後に生成される結果のほとんどは無効ですが、現時点では条件を使用してフィルタリングできます。
1.2 複数テーブルクエリのデカルト積
次に、デカルト積演算を実行する方法を試してみましょう。
まず上記の学生情報テーブルとクラス情報テーブルの2つのテーブルを作成し、作成後に上記のテーブルの内容を追加します。
select * from student;
+----+------+---------+
| id | name | classid |
+----+------+---------+
| 1 | 张三 | 1 |
| 2 | 李四 | 2 |
| 3 | 王五 | 1 |
+----+------+---------+
select * from class;
+---------+-----------+
| classid | classname |
+---------+-----------+
| 1 | 舞蹈班 |
| 2 | 跆拳道班 |
+---------+-----------+
次に、これら 2 つのテーブルに対してデカルト積演算を実行します。
select * from student,class;
+----+------+---------+---------+-----------+
| id | name | classid | classid | classname |
+----+------+---------+---------+-----------+
| 1 | 张三 | 1 | 1 | 舞蹈班 |
| 1 | 张三 | 1 | 2 | 跆拳道班 |
| 2 | 李四 | 2 | 1 | 舞蹈班 |
| 2 | 李四 | 2 | 2 | 跆拳道班 |
| 3 | 王五 | 1 | 1 | 舞蹈班 |
| 3 | 王五 | 1 | 2 | 跆拳道班 |
+----+------+---------+---------+-----------+
上記のデカルト積の実行後に生成される結果のほとんどは無効ですが、現時点では条件を使用してフィルタリングできます。
Student テーブルの classid が class テーブルの classid と等しい場合、このデータは有効なデータです
select * from student,class where classid = classid;
ERROR 1052 (23000): Column 'classid' in where clause is ambiguous
classid = classid を直接使用すると、どのクラス ID がどのクラス ID と比較されるかを判断できないため、エラーが報告されます。
select * from student,class where student.classid = class.classid;
+----+------+---------+---------+-----------+
| id | name | classid | classid | classname |
+----+------+---------+---------+-----------+
| 1 | 张三 | 1 | 1 | 舞蹈班 |
| 2 | 李四 | 2 | 2 | 跆拳道班 |
| 3 | 王五 | 1 | 1 | 舞蹈班 |
+----+------+---------+---------+-----------+
そうするとテーブル名が使えるようになりますカラム名を区別する方法
注: 接続条件に加えて、複数テーブル クエリでは他の条件も追加できます。
複数テーブルのクエリの場合は、複数のテーブルを使用し、カンマで区切って複数のテーブルを接続します。結合に結合を使用したり、内部結合を使用したりすることもできます。
join on は複数テーブル クエリを実装します。
select * from student join class on student.classid = class.classid;
+----+------+---------+---------+-----------+
| id | name | classid | classid | classname |
+----+------+---------+---------+-----------+
| 1 | 张三 | 1 | 1 | 舞蹈班 |
| 2 | 李四 | 2 | 2 | 跆拳道班 |
| 3 | 王五 | 1 | 1 | 舞蹈班 |
+----+------+---------+---------+-----------+
join は 2 つのテーブルを接続し、on の後に接続条件が続きます。
内部結合は複数テーブル クエリを実装します。
select * from student inner join class on student.classid = class.classid;
+----+------+---------+---------+-----------+
| id | name | classid | classid | classname |
+----+------+---------+---------+-----------+
| 1 | 张三 | 1 | 1 | 舞蹈班 |
| 2 | 李四 | 2 | 2 | 跆拳道班 |
| 3 | 王五 | 1 | 1 | 舞蹈班 |
+----+------+---------+---------+-----------+
内部結合は実際には結合と同じなので、ここではあまり説明しません。
複数のテーブルからの結合と結合の主な違いは次のとおりです。
複数のテーブルからは内部結合のみを実現できます
join on は内部結合と外部結合の両方を実現できます
1.3 内部結合と外部結合
内部結合と外部結合の主な違いは次のとおりです。
接続する 2 つのテーブルのデータが 1 対 1 に対応している場合、実際には内部結合と外部結合に違いはありません。
結合する 2 つのテーブルのデータが 1 対 1 ではない場合、内部結合と外部結合には違いがあります。
1.3.1 2 つのテーブル間の 1 対 1 対応
これで、学生テーブルとスコア テーブルの 2 つのテーブルができました。
select * from student;
+----+------+
| id | name |
+----+------+
| 1 | 张三 |
| 2 | 李四 |
| 3 | 王五 |
+----+------+
select * from scoretable;
+-----------+-------+
| studentId | score |
+-----------+-------+
| 1 | 97 |
| 2 | 86 |
| 3 | 73 |
+-----------+-------+
id とstudentId は 1 対 1 に対応しており、すべての内部接続と外部接続の間に違いはありません。
内部結合:
select * from student,scoreTable where student.id = scoretable.studentId;
+----+------+-----------+-------+
| id | name | studentId | score |
+----+------+-----------+-------+
| 1 | 张三 | 1 | 97 |
| 2 | 李四 | 2 | 86 |
| 3 | 王五 | 3 | 73 |
+----+------+-----------+-------+
外部結合:
select * from student join scoreTable on student.id = scoretable.studentId;
+----+------+-----------+-------+
| id | name | studentId | score |
+----+------+-----------+-------+
| 1 | 张三 | 1 | 97 |
| 2 | 李四 | 2 | 86 |
| 3 | 王五 | 3 | 73 |
+----+------+-----------+-------+
1.3.2 2 つのテーブル間には 1 対 1 の対応関係はありません
これで、学生テーブルとスコア テーブルの 2 つのテーブルができました。
select * from student;
+----+------+
| id | name |
+----+------+
| 1 | 张三 |
| 2 | 李四 |
| 3 | 王五 |
+----+------+
select * from scoretable;
+-----------+-------+
| studentId | score |
+-----------+-------+
| 1 | 97 |
| 2 | 86 |
| 6 | 73 |
+-----------+-------+
これで、ID 3 の生徒にはスコアテーブルに対応する StudentId がないことがわかります。
内部結合:
select * from student,scoreTable where student.id = scoretable.studentId;
+----+------+-----------+-------+
| id | name | studentId | score |
+----+------+-----------+-------+
| 1 | 张三 | 1 | 97 |
| 2 | 李四 | 2 | 86 |
+----+------+-----------+-------+
内部接続を実行すると、学生の ID が 3 で、スコアテーブルの StudentId が 6 と一致しないため、スクリーンアウトされ、クエリされません。
外部結合:
2 つのテーブルが 1 対 1 に対応していない場合、外部結合は左外部結合と右外部結合に分けられます。
左外部接続: 左結合オン
select * from student left join scoreTable on student.id = scoretable.studentId;
+----+------+-----------+-------+
| id | name | studentId | score |
+----+------+-----------+-------+
| 1 | 张三 | 1 | 97 |
| 2 | 李四 | 2 | 86 |
| 3 | 王五 | NULL | NULL |
+----+------+-----------+-------+
左外部結合は左テーブルの結果を可能な限り表示します。右テーブルに該当するレコードがない場合はNULLで埋めます。
右外部結合: 右結合オン
select * from student right join scoreTable on student.id = scoretable.studentId;
+------+------+-----------+-------+
| id | name | studentId | score |
+------+------+-----------+-------+
| 1 | 张三 | 1 | 97 |
| 2 | 李四 | 2 | 86 |
| NULL | NULL | 6 | 73 |
+------+------+-----------+-------+
右外部結合は可能な限り右テーブルの結果を表示しますが、左テーブルに該当するレコードがない場合はNULLで埋めてください。
1.4 自己結合
自己結合: それ自体とそれ自体のデカルト積
自己結合の使用シナリオ: 行と行を比較する場合、自己結合を使用して行を列に変換して比較できます。
スコアテーブルとコースの 2 つのテーブルができました。
scoretable 表:
select * from scoretable;
+-------+------------+-----------+
| score | student_id | course_id |
+-------+------------+-----------+
| 70 | 1 | 1 |
| 96 | 1 | 2 |
| 97 | 1 | 3 |
| 80 | 2 | 1 |
| 92 | 2 | 2 |
| 86 | 2 | 3 |
| 91 | 3 | 1 |
| 76 | 3 | 2 |
| 77 | 3 | 3 |
+-------+------------+-----------+
course 表:
select * from course;
+----+------+
| id | name |
+----+------+
| 1 | 语文 |
| 2 | 数学 |
| 3 | 英语 |
+----+------+
次に、どの生徒の中国語スコアが英語のスコアよりも低いかを確認したいと思います。
最初の自己結合では、行を列に変換します。
select * from scoretable,scoretable;
ERROR 1066 (42000): Not unique table/alias: 'scoretable'
自分と自分を結びつける、その名前は繰り返すことはできない
テーブル名を繰り返すことはできないので、どうすれば自己接続できるでしょうか?
回答: エイリアスを作成すると、列を整列させるだけでなく、テーブルを整列させることもできます。
select * from scoretable as s1,scoretable as s2;
自己接続の順列や組み合わせでは無効なデータが大量に生成されるため、接続条件を指定する必要がある
有効なデータを除外するための接続条件を指定します。
select * from scoretable as s1,scoretable as s2
where s1.student_id = s2.student_id;
自己接続の場合、student_id が等しい場合のみ、有効なデータを示します
左側のテーブルに中国語のスコアをクエリし、右側のテーブルに英語のスコアをクエリする条件を追加します。
有効な結果がチェックアウトされたら、左側の中国語スコアと右側の英語スコアをチェックする条件を追加する必要があります。
select * from scoretable as s1,scoretable as s2
where s1.student_id = s2.student_id
and s1.course_id = 1 and s2.course_id = 3;
+-------+------------+-----------+-------+------------+-----------+
| score | student_id | course_id | score | student_id | course_id |
+-------+------------+-----------+-------+------------+-----------+
| 70 | 1 | 1 | 97 | 1 | 3 |
| 80 | 2 | 1 | 86 | 2 | 3 |
| 91 | 3 | 1 | 77 | 3 | 3 |
+-------+------------+-----------+-------+------------+-----------+
このようにして、左側の中国語のスコアがクエリされ、右側の英語のスコアがクエリされます。
中国語のスコアが英語のスコアよりも低い生徒をクエリする条件を追加します。
次のステップは、どの生徒の中国語スコアが英語スコアよりも低いかを確認することです。
select * from scoretable as s1,scoretable as s2
where s1.student_id = s2.student_id
and s1.course_id = 1 and s2.course_id = 3 and s1.score < s2.score;
+-------+------------+-----------+-------+------------+-----------+
| score | student_id | course_id | score | student_id | course_id |
+-------+------------+-----------+-------+------------+-----------+
| 70 | 1 | 1 | 97 | 1 | 3 |
| 80 | 2 | 1 | 86 | 2 | 3 |
+-------+------------+-----------+-------+------------+-----------+
2 rows in set (0.00 sec)
このようにして、中国語のスコアが英語のスコアよりも低い学生の情報を照会することができます。
1.5 サブクエリ
サブクエリ: 複数の SQL を 1 つに結合します。
実際の開発では、サブクエリの使用には注意が必要です。サブクエリは非常に複雑で、理解するのが非常に難しい SQL を構築する可能性があるためです。
コードを書く場合、一般に読みやすさと保守性を追求するか、プログラムの実行速度を追求します。
1.5.1 単一行のサブクエリ
単一行サブクエリ: 1 行のレコードを返すサブクエリ
student 表:
select * from student;
+----+----------+------+
| id | class_id | name |
+----+----------+------+
| 1 | 1 | 张三 |
| 2 | 1 | 李四 |
| 3 | 2 | 王五 |
| 4 | 3 | 赵六 |
| 5 | 2 | 王七 |
+----+----------+------+
次に、「Zhang San」のクラスメートをクエリし、class_id に従ってクエリを実行します。
個別にクエリします:
//查询出张三的class_id
select class_id from student where name = '张三';
+----------+
| class_id |
+----------+
| 1 |
+----------+
//查询出来的张三的class_id为 1,再查询除了张三以外的class_id 为1的同学
select * from student where class_id = 1 and name != '张三';
+----+----------+------+
| id | class_id | name |
+----+----------+------+
| 2 | 1 | 李四 |
+----+----------+------+
単一行のサブクエリ:
select * from student where
class_id = ( select class_id from student where name = '张三')
and name != '张三';
+----+----------+------+
| id | class_id | name |
+----+----------+------+
| 2 | 1 | 李四 |
+----+----------+------+
1.5.2 複数行のサブクエリ
複数行サブクエリ: 複数行のレコードを返すサブクエリ
scoretable 表:
select * from scoretable;
+-------+------------+-----------+
| score | student_id | course_id |
+-------+------------+-----------+
| 70 | 1 | 1 |
| 96 | 1 | 2 |
| 97 | 1 | 3 |
| 80 | 2 | 1 |
| 92 | 2 | 2 |
| 86 | 2 | 3 |
| 91 | 3 | 1 |
| 76 | 3 | 2 |
| 77 | 3 | 3 |
+-------+------------+-----------+
course 表:
select * from course;
+----+------+
| id | name |
+----+------+
| 1 | 语文 |
| 2 | 数学 |
| 3 | 英语 |
+----+------+
各学生の「中国語」「英語」コースのスコア情報を照会
一般的なクエリ:
//首先查询出语文和英语成绩对应的id
select id from course where name = '语文' or name = '英语';
+----+
| id |
+----+
| 1 |
| 3 |
+----+
//再根据查询出来的语文英语对应的id,在 scoretable表中查询
select * from scoretable where course_id = 1 or course_id = 3;
+-------+------------+-----------+
| score | student_id | course_id |
+-------+------------+-----------+
| 70 | 1 | 1 |
| 97 | 1 | 3 |
| 80 | 2 | 1 |
| 86 | 2 | 3 |
| 91 | 3 | 1 |
| 77 | 3 | 3 |
+-------+------------+-----------+
複数行のサブクエリ:
select * from scoretable where course_id
in(select id from course where name = '语文' or name = '英语');
+-------+------------+-----------+
| score | student_id | course_id |
+-------+------------+-----------+
| 70 | 1 | 1 |
| 97 | 1 | 3 |
| 80 | 2 | 1 |
| 86 | 2 | 3 |
| 91 | 3 | 1 |
| 77 | 3 | 3 |
+-------+------------+-----------+
1.5.3 結合クエリ
結合クエリ: 2 つのクエリ結果セットを 1 つに結合します。
実際のアプリケーションでは、複数のクエリの実行結果を結合するために、集合演算子の Union と Union All を使用できます。UNION および UNION ALL を使用する場合、前後のクエリの結果セット内のフィールドは一貫している必要があります。
共用体演算子
Union 演算子は 2 つの結果セットの和集合を取得するために使用されます。この演算子を使用すると、結果セット内の重複行が自動的に削除されます。
course 表:
select * from course;
+----+------+
| id | name |
+----+------+
| 1 | 语文 |
| 2 | 数学 |
| 3 | 英语 |
| 6 | 化学 |
| 7 | 物理 |
+----+------+
ID が 2 以下、または名前が「English」のコース情報をクエリします。
select * from course where id <= 2 union select * from course where name = '英语';
+----+------+
| id | name |
+----+------+
| 1 | 语文 |
| 2 | 数学 |
| 3 | 英语 |
+----+------+
これを見て、「 」または「 」で実現できるのに、なぜ Union を使用するのか?という疑問が生じたかもしれません。
回答: or クエリは、同じテーブルからのみ取得できます。ユニオン クエリが異なるテーブルから取得できる場合、クエリ対象の結果列のみが一致します。一致するのは、同じタイプの列、同じ列名、および列の名前。同じ
すべて結合演算子
Union all 演算子は、2 つの結果セットの和集合を取得するために使用されます。この演算子を使用する場合、結果セット内の重複行は削除されません。
select * from course where id < 3 union all select * from course where name = '数学';
+----+------+
| id | name |
+----+------+
| 1 | 语文 |
| 2 | 数学 |
| 2 | 数学 |
+----+------+