パート1-結合と結合
この回答は次のとおりです。
- パート1
- 内部結合を使用して2つ以上のテーブルを結合する(wikipediaエントリを参照 追加情報について)
- ユニオンクエリの使用方法
- 左外部結合と右外部結合(このstackOverflowの回答 結合の種類を説明するのに最適です)
- クエリを交差させる(およびデータベースがクエリをサポートしていない場合にクエリを再現する方法)-これはSQL-Serverの機能です(情報を参照 )および私がこのすべてを書いた理由 そもそも。
- パート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
であることがわかりました。 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
にリンクするだけではありません。 テーブルだけでなく、すでに結合されているテーブル間の結合も指定します。これが行われなかった場合、結果はデカルト結合と呼ばれます。これは、dbaが悪いことを意味します。デカルト結合は、情報がデータベースに結果を制限する方法を指示していないために行が返される結合であり、クエリはすべてを返します。 基準に一致する行。
したがって、デカルト結合の例を示すために、次のクエリを実行してみましょう。
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
から 。ただし、方法を指定しなかったため テーブルを結合するために、データベースはすべてに一致しています すべての最初のテーブルの行 2番目のテーブルの行。
さて、上司が戻ってきたので、彼はもう一度もっと情報を求めています。 同じリストが必要ですが、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
を使用するとパフォーマンスがわずかに低下することを意味します。 union all
しかし、結果はそれだけの価値があるかもしれません-しかし、私はこの種のことについては推測しません。
このメモについては、ここでいくつかの追加のメモに注意する価値があるかもしれません。
- 結果を並べ替える場合は、
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
を使用できます 加入。これにより、すべてが返されます 他のテーブルで一致するかどうかに関係なく、一方のテーブルの結果:
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
にすることができます。 またはright
タイプ。左または右は、どのテーブルが完全にあるかを定義します 含まれています。 left outer join
左側のテーブルのすべての行が含まれますが、(ご想像のとおり)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ステートメント)を介して交差点を作成できます。
交差点は、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つの異なるテーブル間で交差を実行する場合は、すべての列に結合を作成する必要があります。 テーブルの。