パート1-結合とユニオン
この回答は以下をカバーします:
- パート1
- パート2
- サブクエリ-それらが何であるか、どこで使用できるか、何に注意するか
- デカルトがAKAに加わる-ああ、惨めさ!
データベース内の複数のテーブルからデータを取得するには、いくつかの方法があります。この回答では、ANSI-92結合構文を使用します。これは、古いANSI-89構文を使用します。そこに他のチュートリアルの数と異なる場合があります(あなたが89に使用されている場合や、あまり直感的に見えるかもしれません-しかし、すべて私に言えることは、それを試してみることです)そのままずっと簡単にクエリがより複雑になる時期を理解する。なぜそれを使うのですか?パフォーマンスの向上はありますか?短い答えはノーですが、あるあなたがそれに慣れる読みやすいです。この構文を使用すると、他の人が作成したクエリを読みやすくなります。
また、利用可能な車を追跡するためのデータベースを備えた小さなカーヤードの概念を使用します。所有者はあなたを彼のITコンピュータの男として雇い、あなたが彼が帽子を一滴落とすときに彼が要求するデータを彼が落とせると期待しています。
ファイナルテーブルで使用されるルックアップテーブルをいくつか作成しました。これにより、作業に適したモデルが得られます。まず、次の構造を持つサンプルデータベースに対してクエリを実行します。最初によくある間違いを考えて、何が悪いのかを説明し、もちろん修正方法も示します。
最初の表は単にカラーリストであり、自動車の庭にある色がわかるようになっています。
mysql> create table colors(id int(3) not null auto_increment primary key,
-> color varchar(15), paint varchar(10));
Query OK, 0 rows affected (0.01 sec)
mysql> show columns from colors;
+-------+-------------+------+-----+---------+----------------+
| Field | Type | Null | Key | Default | Extra |
+-------+-------------+------+-----+---------+----------------+
| id | int(3) | NO | PRI | NULL | auto_increment |
| color | varchar(15) | YES | | NULL | |
| paint | varchar(10) | YES | | NULL | |
+-------+-------------+------+-----+---------+----------------+
3 rows in set (0.01 sec)
mysql> insert into colors (color, paint) values ('Red', 'Metallic'),
-> ('Green', 'Gloss'), ('Blue', 'Metallic'),
-> ('White' 'Gloss'), ('Black' 'Gloss');
Query OK, 5 rows affected (0.00 sec)
Records: 5 Duplicates: 0 Warnings: 0
mysql> select * from colors;
+----+-------+----------+
| id | color | paint |
+----+-------+----------+
| 1 | Red | Metallic |
| 2 | Green | Gloss |
| 3 | Blue | Metallic |
| 4 | White | Gloss |
| 5 | Black | Gloss |
+----+-------+----------+
5 rows in set (0.00 sec)
ブランドテーブルは、カーヤードから販売される可能性のある自動車のさまざまなブランドを示しています。
mysql> create table brands (id int(3) not null auto_increment primary key,
-> brand varchar(15));
Query OK, 0 rows affected (0.01 sec)
mysql> show columns from brands;
+-------+-------------+------+-----+---------+----------------+
| Field | Type | Null | Key | Default | Extra |
+-------+-------------+------+-----+---------+----------------+
| id | int(3) | NO | PRI | NULL | auto_increment |
| brand | varchar(15) | YES | | NULL | |
+-------+-------------+------+-----+---------+----------------+
2 rows in set (0.01 sec)
mysql> insert into brands (brand) values ('Ford'), ('Toyota'),
-> ('Nissan'), ('Smart'), ('BMW');
Query OK, 5 rows affected (0.00 sec)
Records: 5 Duplicates: 0 Warnings: 0
mysql> select * from brands;
+----+--------+
| id | brand |
+----+--------+
| 1 | Ford |
| 2 | Toyota |
| 3 | Nissan |
| 4 | Smart |
| 5 | BMW |
+----+--------+
5 rows in set (0.00 sec)
モデルテーブルはさまざまなタイプの車をカバーします。実際の車のモデルではなく、さまざまなタイプの車を使用する方が簡単になります。
mysql> create table models (id int(3) not null auto_increment primary key,
-> model varchar(15));
Query OK, 0 rows affected (0.01 sec)
mysql> show columns from models;
+-------+-------------+------+-----+---------+----------------+
| Field | Type | Null | Key | Default | Extra |
+-------+-------------+------+-----+---------+----------------+
| id | int(3) | NO | PRI | NULL | auto_increment |
| model | varchar(15) | YES | | NULL | |
+-------+-------------+------+-----+---------+----------------+
2 rows in set (0.00 sec)
mysql> insert into models (model) values ('Sports'), ('Sedan'), ('4WD'), ('Luxury');
Query OK, 4 rows affected (0.00 sec)
Records: 4 Duplicates: 0 Warnings: 0
mysql> select * from models;
+----+--------+
| id | model |
+----+--------+
| 1 | Sports |
| 2 | Sedan |
| 3 | 4WD |
| 4 | Luxury |
+----+--------+
4 rows in set (0.00 sec)
そして最後に、これらすべての他のテーブルを結び付けるために、すべてを結び付けるテーブルです。IDフィールドは、実際には車を識別するために使用される一意のロット番号です。
mysql> create table cars (id int(3) not null auto_increment primary key,
-> color int(3), brand int(3), model int(3));
Query OK, 0 rows affected (0.01 sec)
mysql> show columns from cars;
+-------+--------+------+-----+---------+----------------+
| Field | Type | Null | Key | Default | Extra |
+-------+--------+------+-----+---------+----------------+
| id | int(3) | NO | PRI | NULL | auto_increment |
| color | int(3) | YES | | NULL | |
| brand | int(3) | YES | | NULL | |
| model | int(3) | YES | | NULL | |
+-------+--------+------+-----+---------+----------------+
4 rows in set (0.00 sec)
mysql> insert into cars (color, brand, model) values (1,2,1), (3,1,2), (5,3,1),
-> (4,4,2), (2,2,3), (3,5,4), (4,1,3), (2,2,1), (5,2,3), (4,5,1);
Query OK, 10 rows affected (0.00 sec)
Records: 10 Duplicates: 0 Warnings: 0
mysql> select * from cars;
+----+-------+-------+-------+
| id | color | brand | model |
+----+-------+-------+-------+
| 1 | 1 | 2 | 1 |
| 2 | 3 | 1 | 2 |
| 3 | 5 | 3 | 1 |
| 4 | 4 | 4 | 2 |
| 5 | 2 | 2 | 3 |
| 6 | 3 | 5 | 4 |
| 7 | 4 | 1 | 3 |
| 8 | 2 | 2 | 1 |
| 9 | 5 | 2 | 3 |
| 10 | 4 | 5 | 1 |
+----+-------+-------+-------+
10 rows in set (0.00 sec)
これにより、さまざまな種類の結合の以下の例をカバーするのに十分なデータ(私は願っています)が得られ、それらを価値のあるものにするのに十分なデータも得られます。
だから、それの骨子に入ると、ボスは彼が持っているすべてのスポーツカーのIDを知りたがっています。
これは単純な2つのテーブル結合です。モデルを特定するテーブルと、在庫があるテーブルを持っています。ご覧model
のcars
とおり、テーブルの列のデータは、テーブルのmodels
列に関連していますcars
。これで、modelsテーブルのIDが1
forでSports
あることがわかったので、結合を作成しましょう。
select
ID,
model
from
cars
join models
on model=ID
このクエリは適切に見えますか?2つのテーブルを識別し、必要な情報を含め、どの列に結合するかを正しく識別する結合を使用します。
ERROR 1052 (23000): Column 'ID' in field list is ambiguous
ああ!最初のクエリでエラーが発生しました!はい、それは梅です。ご覧のとおり、クエリは実際に正しい列を取得していますが、一部の列は両方のテーブルに存在するため、データベースは実際の列の意味と場所について混乱します。これを解決するには2つの解決策があります。1つ目は素晴らしくてシンプルです。次のtableName.columnName
ように、データベースの意味を正確に伝えるために使用できます。
select
cars.ID,
models.model
from
cars
join models
on cars.model=models.ID
+----+--------+
| ID | model |
+----+--------+
| 1 | Sports |
| 3 | Sports |
| 8 | Sports |
| 10 | Sports |
| 2 | Sedan |
| 4 | Sedan |
| 5 | 4WD |
| 7 | 4WD |
| 9 | 4WD |
| 6 | Luxury |
+----+--------+
10 rows in set (0.00 sec)
もう1つはおそらくより頻繁に使用され、テーブルエイリアスと呼ばれます。この例のテーブルには、簡潔で簡潔な名前が付いていますが、次のように入力するKPI_DAILY_SALES_BY_DEPARTMENT
とおそらくすぐに古くなるため、次のようにテーブルにニックネームを付けるのが簡単な方法です。
select
a.ID,
b.model
from
cars a
join models b
on a.model=b.ID
さて、リクエストに戻ります。ご覧のとおり、必要な情報はありますが、要求されなかった情報もあるため、ステートメントにwhere句を含めて、要求されたとおりのスポーツカーのみを取得する必要があります。テーブル名を何度も使用するよりも、テーブルエイリアス方式を使用する方が好きなので、ここからはそれを使い続けます。
明らかに、クエリにwhere句を追加する必要があります。ID=1
またはでスポーツカーを識別できますmodel='Sports'
。IDにはインデックスが付けられており、主キー(たまたま入力が少ない)なので、クエリでそれを使用できます。
select
a.ID,
b.model
from
cars a
join models b
on a.model=b.ID
where
b.ID=1
+----+--------+
| ID | model |
+----+--------+
| 1 | Sports |
| 3 | Sports |
| 8 | Sports |
| 10 | Sports |
+----+--------+
4 rows in set (0.00 sec)
ビンゴ!上司は幸せです。もちろん、上司であり、彼が求めたことに決して満足していないので、彼は情報を見て、色も欲しいと言いました。
さて、クエリの大部分は既に記述されていますが、色である3番目のテーブルを使用する必要があります。これで、メイン情報テーブルcars
に車の色IDが格納され、これが色ID列にリンクされます。したがって、オリジナルと同様の方法で、3番目のテーブルを結合できます。
select
a.ID,
b.model
from
cars a
join models b
on a.model=b.ID
join colors c
on a.color=c.ID
where
b.ID=1
+----+--------+
| ID | model |
+----+--------+
| 1 | Sports |
| 3 | Sports |
| 8 | Sports |
| 10 | Sports |
+----+--------+
4 rows in set (0.00 sec)
くそー、テーブルは正しく結合され、関連する列はリンクされていましたが、リンクしたばかりの新しいテーブルから実際の情報を取得するのを忘れていました。
select
a.ID,
b.model,
c.color
from
cars a
join models b
on a.model=b.ID
join colors c
on a.color=c.ID
where
b.ID=1
+----+--------+-------+
| ID | model | color |
+----+--------+-------+
| 1 | Sports | Red |
| 8 | Sports | Green |
| 10 | Sports | White |
| 3 | Sports | Black |
+----+--------+-------+
4 rows in set (0.00 sec)
ええ、それはしばらくの間私たちの背中の上司です。では、これについてもう少し詳しく説明します。ご覧のとおりfrom
、ステートメントの句はメインテーブルをリンクしています(私は、ルックアップテーブルやディメンションテーブルではなく、情報を含むテーブルを使用することがよくあります。クエリはすべてのテーブルを切り替えて使用しても同様に機能しますが、数か月後にこのクエリに戻ってそれを読むので、多くの場合、わかりやすくてわかりやすいクエリを作成することをお勧めします。直感的にレイアウトし、すべてができるだけ明確になるように、適切なインデントを使用してください。他の人に教えることを続ける場合は、特にトラブルシューティングを行う場合は、これらの特性をクエリに植え込むようにしてください。
この方法でより多くのテーブルをリンクし続けることは完全に可能です。
select
a.ID,
b.model,
c.color
from
cars a
join models b
on a.model=b.ID
join colors c
on a.color=c.ID
join brands d
on a.brand=d.ID
where
b.ID=1
join
ステートメントに複数の列を結合する可能性があるテーブルを含めるのを忘れていましたが、ここに例を示します。models
テーブルにブランド固有のモデルがあり、そのため、フィールドbrand
のbrands
テーブルにリンクして戻ると呼ばれる列があった場合、次のID
ように行うことができます。
select
a.ID,
b.model,
c.color
from
cars a
join models b
on a.model=b.ID
join colors c
on a.color=c.ID
join brands d
on a.brand=d.ID
and b.brand=d.ID
where
b.ID=1
上記のクエリは、結合されたテーブルをメインテーブルにリンクするだけでなくcars
、既に結合されたテーブル間の結合も指定しています。これが行われなかった場合、結果はデカルト結合と呼ばれます。デカルト結合は、情報がデータベースに結果の制限方法を指示しないため行が返される結合であり、クエリは基準に一致するすべての行を返します。
したがって、デカルト結合の例を示すために、次のクエリを実行してみましょう。
select
a.ID,
b.model
from
cars a
join models b
+----+--------+
| ID | model |
+----+--------+
| 1 | Sports |
| 1 | Sedan |
| 1 | 4WD |
| 1 | Luxury |
| 2 | Sports |
| 2 | Sedan |
| 2 | 4WD |
| 2 | Luxury |
| 3 | Sports |
| 3 | Sedan |
| 3 | 4WD |
| 3 | Luxury |
| 4 | Sports |
| 4 | Sedan |
| 4 | 4WD |
| 4 | Luxury |
| 5 | Sports |
| 5 | Sedan |
| 5 | 4WD |
| 5 | Luxury |
| 6 | Sports |
| 6 | Sedan |
| 6 | 4WD |
| 6 | Luxury |
| 7 | Sports |
| 7 | Sedan |
| 7 | 4WD |
| 7 | Luxury |
| 8 | Sports |
| 8 | Sedan |
| 8 | 4WD |
| 8 | Luxury |
| 9 | Sports |
| 9 | Sedan |
| 9 | 4WD |
| 9 | Luxury |
| 10 | Sports |
| 10 | Sedan |
| 10 | 4WD |
| 10 | Luxury |
+----+--------+
40 rows in set (0.00 sec)
なんてこった、醜い。ただし、データベースに関する限り、それはまさに要求されたものです。クエリでは、我々は用を求めたID
からcars
とmodel
からmodels
。我々が指定されていませんでしたので、しかし、どのようにテーブルを結合するために、データベースが一致したすべてのと最初のテーブルから行をすべての第二のテーブルからの行。
さて、上司が戻ってきたので、もう一度情報を求めています。同じリストが必要ですが、4WDも含めます。
ただし、これは、これを達成するための2つの異なる方法を検討するための大きな言い訳になります。次のようにwhere句に別の条件を追加できます。
select
a.ID,
b.model,
c.color
from
cars a
join models b
on a.model=b.ID
join colors c
on a.color=c.ID
join brands d
on a.brand=d.ID
where
b.ID=1
or b.ID=3
上記は完璧に機能しますが、別の見方をすると、これはunion
クエリがどのように機能するかを示す優れた言い訳です。
次のようにすると、すべてのスポーツカーが返されます。
select
a.ID,
b.model,
c.color
from
cars a
join models b
on a.model=b.ID
join colors c
on a.color=c.ID
join brands d
on a.brand=d.ID
where
b.ID=1
そして、以下はすべての4WDを返します。
select
a.ID,
b.model,
c.color
from
cars a
join models b
on a.model=b.ID
join colors c
on a.color=c.ID
join brands d
on a.brand=d.ID
where
b.ID=3
したがって、union all
それらの間に句を追加すると、2番目のクエリの結果が最初のクエリの結果に追加されます。
select
a.ID,
b.model,
c.color
from
cars a
join models b
on a.model=b.ID
join colors c
on a.color=c.ID
join brands d
on a.brand=d.ID
where
b.ID=1
union all
select
a.ID,
b.model,
c.color
from
cars a
join models b
on a.model=b.ID
join colors c
on a.color=c.ID
join brands d
on a.brand=d.ID
where
b.ID=3
+----+--------+-------+
| ID | model | color |
+----+--------+-------+
| 1 | Sports | Red |
| 8 | Sports | Green |
| 10 | Sports | White |
| 3 | Sports | Black |
| 5 | 4WD | Green |
| 7 | 4WD | White |
| 9 | 4WD | Black |
+----+--------+-------+
7 rows in set (0.00 sec)
ご覧のとおり、最初のクエリの結果が最初に返され、次に2番目のクエリの結果が返されます。
この例では、もちろん最初のクエリを使用する方がはるかに簡単union
ですが、特定のケースではクエリが優れている場合があります。これらは、簡単に結合できないテーブルからテーブルから特定の結果を返すための優れた方法です-またはさらに言えば、完全に無関係なテーブル。ただし、従うべきルールがいくつかあります。
- 最初のクエリの列タイプは、以下の他のすべてのクエリの列タイプと一致する必要があります。
- 最初のクエリの列の名前は、結果セット全体を識別するために使用されます。
- 各クエリの列数は同じでなければなりません。
さて、あなたは可能性があるか疑問に思うことの違いは、使用の間にあるunion
とunion all
。union
一方、クエリは、重複を削除しますunion all
しません。これは、union
over を使用しunion all
たときにパフォーマンスにわずかな影響があることを意味しますが、結果はそれだけの価値がある可能性があります。ただし、このようなことについては推測しません。
このノートについては、ここでいくつかの追加のノートに注目する価値があるかもしれません。
- 結果を並べ替える場合は、anを使用
order by
できますが、エイリアスは使用できません。上記のクエリでorder by a.ID
は、両方のクエリで同じエイリアスが使用されている場合でも、結果を考慮すると、列を呼び出すのID
ではなくa.ID
-を追加するとエラーが発生します。
order by
ステートメントは1つしか持てず、それが最後のステートメントでなければなりません。
次の例では、テーブルに行をいくつか追加しています。
Holden
ブランド表に追加しました。またcars
、color
値が12
-の色テーブルで参照されていない行を追加しました。
さて、上司が再び戻ってきて、リクエストが鳴り響きました-*私たちは、私たちが運ぶ各ブランドとその中の車の数を数えたいです! 。
Rightyoなので、最初に必要なことは、可能なブランドの完全なリストを取得することです。
select
a.brand
from
brands a
+--------+
| brand |
+--------+
| Ford |
| Toyota |
| Nissan |
| Smart |
| BMW |
| Holden |
+--------+
6 rows in set (0.00 sec)
これを車のテーブルに結合すると、次の結果が得られます。
select
a.brand
from
brands a
join cars b
on a.ID=b.brand
group by
a.brand
+--------+
| brand |
+--------+
| BMW |
| Ford |
| Nissan |
| Smart |
| Toyota |
+--------+
5 rows in set (0.00 sec)
もちろんこれは問題Holden
です。私が追加した素敵なブランドについての言及はありません。
これは、結合が両方のテーブルで一致する行を探すためです。タイプの車にはデータHolden
がないため、返されません。ここでouter
結合を使用できます。これは、他のテーブルで一致するかどうかに関係なく、1つのテーブルからすべての結果を返します。
select
a.brand
from
brands a
left outer join cars b
on a.ID=b.brand
group by
a.brand
+--------+
| brand |
+--------+
| BMW |
| Ford |
| Holden |
| Nissan |
| Smart |
| Toyota |
+--------+
6 rows in set (0.00 sec)
これで準備ができたので、素敵な集計関数を追加してカウントを取得し、少しの間ボスを背負わせることができます。
select
a.brand,
count(b.id) as countOfBrand
from
brands a
left outer join cars b
on a.ID=b.brand
group by
a.brand
+--------+--------------+
| brand | countOfBrand |
+--------+--------------+
| BMW | 2 |
| Ford | 2 |
| Holden | 0 |
| Nissan | 1 |
| Smart | 1 |
| Toyota | 5 |
+--------+--------------+
6 rows in set (0.00 sec)
それで、ボスは頭をかしげます。
これをさらに詳しく説明するために、外部結合はleft
or right
型にすることができます。左または右は、どのテーブルが完全に含まれるかを定義します。A left outer join
は左側のテーブルのすべての行を含みますが、(ご想像のとおり)a right outer join
は右側のテーブルのすべての結果を結果に取り込みます。
一部のデータベースではfull outer join
、両方のテーブルから(一致するかどうかにかかわらず)結果を返すを許可しますが、これはすべてのデータベースでサポートされているわけではありません。
さて、おそらくこの時点で、クエリで結合タイプをマージできるかどうか疑問に思っています-答えは「はい」です。
select
b.brand,
c.color,
count(a.id) as countOfBrand
from
cars a
right outer join brands b
on b.ID=a.brand
join colors c
on a.color=c.ID
group by
a.brand,
c.color
+--------+-------+--------------+
| brand | color | countOfBrand |
+--------+-------+--------------+
| Ford | Blue | 1 |
| Ford | White | 1 |
| Toyota | Black | 1 |
| Toyota | Green | 2 |
| Toyota | Red | 1 |
| Nissan | Black | 1 |
| Smart | White | 1 |
| BMW | Blue | 1 |
| BMW | White | 1 |
+--------+-------+--------------+
9 rows in set (0.00 sec)
それで、なぜそれが期待された結果ではないのですか?車からブランドへの外部結合を選択しましたが、結合色では指定されなかったため、特定の結合では両方のテーブルに一致する結果のみが返されます。
以下は、期待した結果を取得するために機能するクエリです。
select
a.brand,
c.color,
count(b.id) as countOfBrand
from
brands a
left outer join cars b
on a.ID=b.brand
left outer join colors c
on b.color=c.ID
group by
a.brand,
c.color
+--------+-------+--------------+
| brand | color | countOfBrand |
+--------+-------+--------------+
| BMW | Blue | 1 |
| BMW | White | 1 |
| Ford | Blue | 1 |
| Ford | White | 1 |
| Holden | NULL | 0 |
| Nissan | Black | 1 |
| Smart | White | 1 |
| Toyota | NULL | 1 |
| Toyota | Black | 1 |
| Toyota | Green | 2 |
| Toyota | Red | 1 |
+--------+-------+--------------+
11 rows in set (0.00 sec)
ご覧のとおり、クエリに2つの外部結合があり、期待どおりに結果が出ています。
さて、あなたが尋ねる他の種類の結合はどうですか?交差点はどうですか?
まあ、すべてのデータベースがサポートしているわけではありませんが、ほとんどすべてのデータベースでintersection
、結合(または少なくとも構造化されたwhereステートメント)を使用して交差を作成できます。
Intersectionは、union
上記のと多少似たタイプの結合ですが、違いは、ユニオンによって結合されたさまざまな個々のクエリ間で同一の(そして私が同一であることを意味する)データの行のみを返すことです。すべての点で同一の行のみが返されます。
簡単な例は次のとおりです。
select
*
from
colors
where
ID>2
intersect
select
*
from
colors
where
id<4
通常のunion
クエリはテーブルのすべての行を返します(最初のクエリは何でも返しID>2
、2番目のクエリはを返しますID<4
)。これにより、完全なセットが生成されますが、交差クエリid=3
は両方の基準を満たすため、一致する行のみを返します。
これで、データベースがintersect
クエリをサポートしていない場合、上記は次のクエリで簡単に実現できます。
select
a.ID,
a.color,
a.paint
from
colors a
join colors b
on a.ID=b.ID
where
a.ID>2
and b.ID<4
+----+-------+----------+
| ID | color | paint |
+----+-------+----------+
| 3 | Blue | Metallic |
+----+-------+----------+
1 row in set (0.00 sec)
本質的に交差クエリをサポートしていないデータベースを使用して2つの異なるテーブル間で交差を実行する場合は、テーブルのすべての列に結合を作成する必要があります。