Teil 1 - Beitritte und Gewerkschaften
Diese Antwort umfasst:
- Teil 1
- Teil 2
- Unterabfragen - was sie sind, wo sie verwendet werden können und worauf zu achten ist
- Cartesian tritt der AKA bei - Oh, das Elend!
Es gibt verschiedene Möglichkeiten, Daten aus mehreren Tabellen in einer Datenbank abzurufen. In dieser Antwort verwende ich die ANSI-92-Join-Syntax. Dies unterscheidet sich möglicherweise von einer Reihe anderer Tutorials, die die ältere ANSI-89-Syntax verwenden (und wenn Sie an 89 gewöhnt sind, scheint dies viel weniger intuitiv zu sein - aber ich kann nur sagen, es zu versuchen), da es viel einfacher ist zu verstehen, wann die Abfragen komplexer werden. Warum es benutzen? Gibt es einen Leistungsgewinn? Die kurze Antwort lautet nein, aber es ist einfacher zu lesen, wenn Sie sich daran gewöhnt haben. Mit dieser Syntax ist es einfacher, Abfragen zu lesen, die von anderen Personen geschrieben wurden.
Ich werde auch das Konzept eines kleinen Karyards verwenden, der über eine Datenbank verfügt, um zu verfolgen, welche Autos verfügbar sind. Der Eigentümer hat Sie als seinen IT-Computer-Mitarbeiter eingestellt und erwartet, dass Sie ihm die Daten, nach denen er fragt, im Handumdrehen löschen können.
Ich habe eine Reihe von Nachschlagetabellen erstellt, die vom Final Table verwendet werden. Dies gibt uns ein vernünftiges Modell, nach dem wir arbeiten können. Zu Beginn führe ich meine Abfragen für eine Beispieldatenbank mit der folgenden Struktur aus. Ich werde versuchen, an häufige Fehler zu denken, die beim Start gemacht werden, und erklären, was mit ihnen schief geht - und natürlich zeigen, wie man sie korrigiert.
Die erste Tabelle ist einfach eine Farbliste, damit wir wissen, welche Farben wir im Autohof haben.
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)
Die Markentabelle identifiziert die verschiedenen Marken der Autos, die Caryard möglicherweise verkaufen könnte.
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)
Die Modelltabelle deckt verschiedene Fahrzeugtypen ab. Es wird einfacher sein, unterschiedliche Fahrzeugtypen als tatsächliche Fahrzeugmodelle zu verwenden.
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)
Und schließlich, um all diese anderen Tische zusammenzubinden, den Tisch, der alles zusammenhält. Das ID-Feld ist tatsächlich die eindeutige Chargennummer, mit der Autos identifiziert werden.
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)
Dies gibt uns genügend Daten (ich hoffe), um die folgenden Beispiele für verschiedene Arten von Verknüpfungen abzudecken, und gibt auch genügend Daten, damit sie sich lohnen.
Der Chef möchte also die IDs aller Sportwagen kennen, die er hat .
Dies ist ein einfacher Join mit zwei Tabellen. Wir haben eine Tabelle, die das Modell und die Tabelle mit dem verfügbaren Bestand identifiziert. Wie Sie sehen können, beziehen sich die Daten in der model
Spalte der cars
Tabelle auf die models
Spalte der cars
Tabelle, die wir haben. Jetzt wissen wir, dass die Modelltabelle eine ID von 1
für hat, Sports
also schreiben wir den Join.
select
ID,
model
from
cars
join models
on model=ID
Diese Abfrage sieht also gut aus, oder? Wir haben die beiden Tabellen identifiziert und enthalten die benötigten Informationen. Wir verwenden einen Join, der korrekt angibt, an welchen Spalten verbunden werden soll.
ERROR 1052 (23000): Column 'ID' in field list is ambiguous
Oh nein! Ein Fehler in unserer ersten Abfrage! Ja, und es ist eine Pflaume. Sie sehen, die Abfrage hat zwar die richtigen Spalten, aber einige davon sind in beiden Tabellen vorhanden, sodass die Datenbank verwirrt darüber ist, welche Spalte wir tatsächlich meinen und wo. Es gibt zwei Lösungen, um dies zu lösen. Das erste ist nett und einfach, wir können verwenden tableName.columnName
, um der Datenbank genau zu sagen, was wir meinen, so:
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)
Das andere wird wahrscheinlich häufiger verwendet und als Tabellenaliasing bezeichnet. Die Tabellen in diesem Beispiel haben nette und kurze einfache Namen, aber das Eingeben von so etwas KPI_DAILY_SALES_BY_DEPARTMENT
würde wahrscheinlich schnell alt werden. Eine einfache Möglichkeit besteht darin, die Tabelle wie folgt zu benennen:
select
a.ID,
b.model
from
cars a
join models b
on a.model=b.ID
Nun zurück zur Anfrage. Wie Sie sehen, haben wir die Informationen, die wir benötigen, aber wir haben auch Informationen, die nicht angefordert wurden. Daher müssen wir eine where-Klausel in die Erklärung aufnehmen, um nur die Sportwagen zu erhalten, wie sie angefordert wurden. Da ich die Tabellenalias-Methode bevorzuge, anstatt die Tabellennamen immer wieder zu verwenden, werde ich mich ab diesem Punkt daran halten.
Natürlich müssen wir unserer Abfrage eine where-Klausel hinzufügen. Wir können Sportwagen entweder durch ID=1
oder identifizieren model='Sports'
. Da die ID indiziert ist und der Primärschlüssel (und zufällig weniger eingegeben wird), können Sie dies in unserer Abfrage verwenden.
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)
Bingo! Der Chef ist glücklich. Da er ein Chef ist und nie glücklich mit dem ist, wonach er gefragt hat, schaut er sich die Informationen an und sagt dann, ich möchte auch die Farben .
Okay, wir haben einen Großteil unserer Abfrage bereits geschrieben, aber wir müssen eine dritte Tabelle verwenden, die Farben enthält. In unserer Hauptinformationstabelle wird nun cars
die Fahrzeugfarb-ID gespeichert und diese führt zurück zur Spalte Farb-ID. Ähnlich wie beim Original können wir uns also einer dritten Tabelle anschließen:
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)
Verdammt, obwohl die Tabelle korrekt verknüpft und die zugehörigen Spalten verknüpft waren, haben wir vergessen, die tatsächlichen Informationen aus der neuen Tabelle abzurufen, die wir gerade verknüpft haben.
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)
Richtig, das ist für einen Moment der Boss von unserem Rücken. Um dies etwas näher zu erläutern. Wie Sie sehen können, from
verknüpft die Klausel in unserer Anweisung unsere Haupttabelle (ich verwende häufig eine Tabelle, die Informationen anstelle einer Nachschlagetabelle oder Dimensionstabelle enthält. Die Abfrage funktioniert genauso gut, wenn alle Tabellen vertauscht sind, ist aber weniger sinnvoll, wenn Wir kommen auf diese Abfrage zurück, um sie in ein paar Monaten zu lesen. Daher ist es oft am besten, eine Abfrage zu schreiben, die schön und leicht zu verstehen ist. Legen Sie sie intuitiv an und verwenden Sie einen schönen Einzug, damit alles so klar wie möglich ist Wenn Sie andere unterrichten, versuchen Sie, diese Eigenschaften in ihre Abfragen einzubinden - insbesondere, wenn Sie Fehler beheben.
Es ist durchaus möglich, immer mehr Tabellen auf diese Weise zu verknüpfen.
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
Während ich vergessen habe, eine Tabelle aufzunehmen, in der wir möglicherweise mehr als eine Spalte in die join
Anweisung einfügen möchten , ist hier ein Beispiel. Wenn die models
Tabelle markenspezifische Modelle und daher auch eine Spalte mit dem Namen hat, brand
die mit der brands
Tabelle auf dem ID
Feld verknüpft ist , könnte dies folgendermaßen geschehen:
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
Sie können sehen, dass die obige Abfrage nicht nur die verknüpften Tabellen mit der cars
Haupttabelle verknüpft , sondern auch Verknüpfungen zwischen den bereits verknüpften Tabellen angibt. Wenn dies nicht getan wurde, wird das Ergebnis als kartesische Verknüpfung bezeichnet - was dba für schlecht spricht. Bei einem kartesischen Join werden Zeilen zurückgegeben, da die Informationen der Datenbank nicht mitteilen, wie die Ergebnisse eingeschränkt werden sollen. Daher gibt die Abfrage alle Zeilen zurück, die den Kriterien entsprechen.
Um ein Beispiel für eine kartesische Verknüpfung zu geben, führen Sie die folgende Abfrage aus:
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)
Guter Gott, das ist hässlich. In Bezug auf die Datenbank ist es jedoch genau das , wonach gefragt wurde. In der Abfrage haben wir nach dem ID
von cars
und dem model
von gefragt models
. Da wir jedoch nicht angegeben haben, wie die Tabellen verknüpft werden sollen, hat die Datenbank jede Zeile aus der ersten Tabelle mit jeder Zeile aus der zweiten Tabelle abgeglichen .
Okay, der Chef ist zurück und möchte wieder mehr Informationen. Ich möchte die gleiche Liste, aber auch 4WDs darin enthalten .
Dies gibt uns jedoch eine gute Ausrede, zwei verschiedene Wege zu betrachten, um dies zu erreichen. Wir könnten der where-Klausel eine weitere Bedingung hinzufügen:
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
Obwohl das oben Genannte perfekt funktioniert, sehen wir es uns anders an. Dies ist eine gute Ausrede, um zu zeigen, wie eine union
Abfrage funktioniert.
Wir wissen, dass im Folgenden alle Sportwagen zurückgegeben werden:
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
Und das Folgende würde alle 4WDs zurückgeben:
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
Durch Hinzufügen einer union all
Klausel zwischen ihnen werden die Ergebnisse der zweiten Abfrage an die Ergebnisse der ersten Abfrage angehängt.
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)
Wie Sie sehen, werden die Ergebnisse der ersten Abfrage zuerst zurückgegeben, gefolgt von den Ergebnissen der zweiten Abfrage.
In diesem Beispiel wäre es natürlich viel einfacher gewesen, einfach die erste Abfrage zu verwenden, aber union
Abfragen können für bestimmte Fälle großartig sein. Sie sind eine großartige Möglichkeit, bestimmte Ergebnisse aus Tabellen aus Tabellen zurückzugeben, die nicht einfach miteinander verbunden werden können - oder aus völlig unabhängigen Tabellen. Es gibt jedoch einige Regeln zu befolgen.
- Die Spaltentypen aus der ersten Abfrage müssen mit den Spaltentypen aus jeder anderen Abfrage unten übereinstimmen.
- Die Namen der Spalten aus der ersten Abfrage werden verwendet, um die gesamte Ergebnismenge zu identifizieren.
- Die Anzahl der Spalten in jeder Abfrage muss gleich sein.
Jetzt fragen Sie sich vielleicht , was der Unterschied zwischen der Verwendung von union
und ist union all
. Eine union
Abfrage entfernt Duplikate, eine union all
nicht. Dies bedeutet, dass es bei der Verwendung von union
over einen kleinen Leistungseinbruch gibt, union all
aber die Ergebnisse können sich lohnen - ich werde jedoch nicht darüber spekulieren.
In diesem Zusammenhang sollten einige zusätzliche Hinweise erwähnt werden.
- Wenn wir die Ergebnisse bestellen wollten, können wir einen verwenden,
order by
aber Sie können den Alias nicht mehr verwenden. In der obigen Abfrage order by a.ID
würde das Anhängen eines zu einem Fehler führen - was die Ergebnisse betrifft, wird die Spalte ID
eher aufgerufen als a.ID
- obwohl in beiden Abfragen derselbe Alias verwendet wurde.
- Wir können nur eine
order by
Aussage haben, und es muss die letzte sein.
Für die nächsten Beispiele füge ich unseren Tabellen einige zusätzliche Zeilen hinzu.
Ich habe Holden
der Markentabelle hinzugefügt . Ich habe auch eine Zeile hinzugefügt cars
, die den color
Wert 12
- hat und die keinen Bezug in der Farbtabelle hat.
Okay, der Chef ist wieder da und bellt Anfragen an - * Ich möchte eine Zählung jeder Marke, die wir führen, und der Anzahl der Autos darin! `- Typischerweise kommen wir nur zu einem interessanten Abschnitt unserer Diskussion und der Chef möchte mehr Arbeit .
Richtig, das erste, was wir tun müssen, ist eine vollständige Liste möglicher Marken zu erhalten.
select
a.brand
from
brands a
+--------+
| brand |
+--------+
| Ford |
| Toyota |
| Nissan |
| Smart |
| BMW |
| Holden |
+--------+
6 rows in set (0.00 sec)
Wenn wir dies nun mit unserem Autotisch verbinden, erhalten wir das folgende Ergebnis:
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)
Was natürlich ein Problem ist - wir sehen keine Erwähnung der schönen Holden
Marke, die ich hinzugefügt habe.
Dies liegt daran, dass ein Join in beiden Tabellen nach übereinstimmenden Zeilen sucht . Da in Fahrzeugen vom Typ keine Daten vorhanden sind, werden Holden
diese nicht zurückgegeben. Hier können wir einen outer
Join verwenden. Dadurch werden alle Ergebnisse einer Tabelle zurückgegeben, unabhängig davon, ob sie mit der anderen Tabelle übereinstimmen oder nicht:
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)
Jetzt, wo wir das haben, können wir eine schöne Aggregatfunktion hinzufügen, um eine Zählung zu erhalten und den Chef für einen Moment von unserem Rücken zu bekommen.
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)
Und damit schleicht sich der Chef weg.
Um dies näher zu erläutern, können äußere Verknüpfungen vom Typ left
oder sein right
. Links oder rechts definiert, welche Tabelle vollständig enthalten ist. A left outer join
enthält alle Zeilen aus der Tabelle links, während (Sie haben es erraten) a right outer join
alle Ergebnisse aus der Tabelle rechts in die Ergebnisse einbringt.
Einige Datenbanken erlauben eine, full outer join
die Ergebnisse (ob übereinstimmend oder nicht) aus beiden Tabellen zurückbringt , dies wird jedoch nicht in allen Datenbanken unterstützt.
Nun, ich nehme an, zu diesem Zeitpunkt fragen Sie sich wahrscheinlich, ob Sie Join-Typen in einer Abfrage zusammenführen können oder nicht - und die Antwort lautet: Ja, das können Sie absolut.
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)
Warum sind das nicht die erwarteten Ergebnisse? Dies liegt daran, dass wir zwar die äußere Verknüpfung von Autos zu Marken ausgewählt haben, diese jedoch nicht in der Verknüpfung zu Farben angegeben wurde. Daher führt diese bestimmte Verknüpfung nur zu Ergebnissen, die in beiden Tabellen übereinstimmen.
Hier ist die Abfrage, die funktionieren würde, um die erwarteten Ergebnisse zu erzielen:
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)
Wie wir sehen können, haben wir zwei äußere Verknüpfungen in der Abfrage und die Ergebnisse kommen wie erwartet durch.
Wie wäre es nun mit den anderen Arten von Joins, die Sie fragen? Was ist mit Kreuzungen?
Nun, nicht alle Datenbanken unterstützen das, intersection
aber so ziemlich alle Datenbanken ermöglichen es Ihnen, eine Schnittmenge durch einen Join (oder zumindest eine gut strukturierte where-Anweisung) zu erstellen.
Ein Schnittpunkt ist eine Art von Verknüpfung, die einer union
wie oben beschrieben ähnelt. Der Unterschied besteht jedoch darin, dass nur Datenzeilen zurückgegeben werden, die zwischen den verschiedenen einzelnen Abfragen, die durch die Vereinigung verbunden sind, identisch sind (und ich meine identisch). Es werden nur Zeilen zurückgegeben, die in jeder Hinsicht identisch sind.
Ein einfaches Beispiel wäre als solches:
select
*
from
colors
where
ID>2
intersect
select
*
from
colors
where
id<4
Während eine normale union
Abfrage alle Zeilen der Tabelle zurückgeben würde (die erste Abfrage gibt etwas zurück ID>2
und die zweite etwas ID<4
), was zu einem vollständigen Satz führen würde, würde eine Schnittabfrage nur die Zeilenübereinstimmung zurückgeben, id=3
da sie beide Kriterien erfüllt.
Wenn Ihre Datenbank eine intersect
Abfrage nicht unterstützt , kann die oben genannte Abfrage problemlos mit der folgenden Abfrage ausgeführt werden:
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)
Wenn Sie eine Schnittmenge zwischen zwei verschiedenen Tabellen mithilfe einer Datenbank ausführen möchten, die von Natur aus keine Schnittpunktabfrage unterstützt, müssen Sie für jede Spalte der Tabellen einen Join erstellen .
Ok, ich fand diesen Beitrag sehr interessant und möchte einige meiner Kenntnisse über das Erstellen einer Abfrage teilen. Danke für diesen Fluffeh . Andere, die dies lesen und das Gefühl haben, dass ich falsch liege, können meine Antwort zu 101% bearbeiten und kritisieren. ( Ehrlich gesagt bin ich sehr dankbar, dass ich meine Fehler korrigiert habe. )
Ich werde einige der häufig gestellten Fragen im
MySQL
Tag veröffentlichen.Trick Nr. 1 ( Zeilen, die mehreren Bedingungen entsprechen )
Angesichts dieses Schemas
FRAGE
Finden Sie alle Filme , die auf zumindest gehören beide
Comedy
undRomance
Kategorien.Lösung
Diese Frage kann manchmal sehr schwierig sein. Es scheint, dass eine solche Abfrage die Antwort sein wird: -
SQLFiddle-Demo
Das ist definitiv sehr falsch, weil es kein Ergebnis liefert . Die Erklärung dafür ist, dass es
CategoryName
in jeder Zeile nur einen gültigen Wert von gibt . Beispielsweise gibt die erste Bedingung true zurück , die zweite Bedingung ist immer false. Bei Verwendung desAND
Operators sollten also beide Bedingungen erfüllt sein. Andernfalls ist es falsch. Eine andere Abfrage ist wie folgt:SQLFiddle-Demo
und das Ergebnis ist immer noch falsch, da es mit einem Datensatz übereinstimmt, der mindestens eine Übereinstimmung enthält
categoryName
. Die wirkliche Lösung wäre, die Anzahl der Aufzeichnungsinstanzen pro Film zu zählen . Die Anzahl der Instanzen sollte mit der Gesamtzahl der in der Bedingung angegebenen Werte übereinstimmen.SQLFiddle Demo (die Antwort)
Trick Nr. 2 ( maximaler Rekord für jeden Eintrag )
Gegebenes Schema,
FRAGE
Finden Sie die neueste Version für jede Software. Zeigen Sie die folgenden Spalten:
SoftwareName
,Descriptions
,LatestVersion
( aus VersionNo Spalte ),DateReleased
Lösung
Einige SQL-Entwickler verwenden fälschlicherweise die
MAX()
Aggregatfunktion. Sie neigen dazu, so zu kreieren,SQLFiddle-Demo
(Die meisten RDBMS erzeugen hierzu einen Syntaxfehler, da einige der nicht aggregierten Spalten in der
group by
Klausel nicht angegeben werden. ) Das Ergebnis erzeugtLatestVersion
auf jeder Software das Richtige, aber offensichtlichDateReleased
sind sie falsch.MySQL
wird nicht unterstütztWindow Functions
undCommon Table Expression
doch wie einige RDBMS bereits. Die Problemumgehung für dieses Problem besteht darin, ein zu erstellen,subquery
das das individuelle MaximumversionNo
für jede Software erhält und später für die anderen Tabellen verknüpft wird.SQLFiddle Demo (die Antwort)
Das war es also. Ich werde bald eine weitere veröffentlichen, sobald ich mich an andere FAQ zum
MySQL
Tag erinnere . Vielen Dank, dass Sie diesen kleinen Artikel gelesen haben. Ich hoffe, dass Sie zumindest noch ein wenig Wissen daraus haben.UPDATE 1
Trick Nr. 3 ( Finden des neuesten Datensatzes zwischen zwei IDs )
Gegebenes Schema
FRAGE
Finden Sie die neueste Konversation zwischen zwei Benutzern.
Lösung
SQLFiddle-Demo
quelle
comedy
und vorzunehmenromance
.Having
passt dann nicht ..distinct
die have- Klausel SQLFiddle Demo hinzufügen : DTeil 2 - Unterabfragen
Okay, jetzt ist der Chef wieder eingebrochen - ich möchte eine Liste aller unserer Autos mit der Marke und insgesamt, wie viele dieser Marken wir haben!
Dies ist eine großartige Gelegenheit, den nächsten Trick in unserer Tasche mit SQL-Extras zu verwenden - die Unterabfrage. Wenn Sie mit dem Begriff nicht vertraut sind, ist eine Unterabfrage eine Abfrage, die in einer anderen Abfrage ausgeführt wird. Es gibt viele verschiedene Möglichkeiten, sie zu verwenden.
Lassen Sie uns für unsere Anfrage zunächst eine einfache Abfrage zusammenstellen, in der jedes Auto und jede Marke aufgelistet sind:
Wenn wir nur die Anzahl der Autos nach Marke sortieren wollen, können wir natürlich Folgendes schreiben:
Wir sollten also in der Lage sein, einfach die Zählfunktion zu unserer ursprünglichen Abfrage hinzuzufügen, oder?
Nein, das können wir leider nicht. Der Grund dafür ist, dass wir beim Hinzufügen der Fahrzeug-ID (Spalte a.ID) diese zur Gruppe hinzufügen müssen, indem - wenn die Zählfunktion funktioniert, nur eine ID pro ID übereinstimmt.
Hier können wir jedoch eine Unterabfrage verwenden - tatsächlich können wir zwei völlig unterschiedliche Arten von Unterabfragen durchführen, die die gleichen Ergebnisse liefern, die wir dafür benötigen. Die erste besteht darin, die Unterabfrage einfach in die
select
Klausel einzufügen . Dies bedeutet, dass jedes Mal, wenn wir eine Datenzeile abrufen, die Unterabfrage ausgeführt wird, eine Datenspalte abruft und diese dann in unsere Datenzeile einfügt.Und Bam!, Das würde uns tun. Wenn Sie jedoch bemerkt haben, muss diese Unterabfrage für jede einzelne Datenzeile ausgeführt werden, die wir zurückgeben. Selbst in diesem kleinen Beispiel haben wir nur fünf verschiedene Automarken, aber die Unterabfrage wurde elf Mal ausgeführt, da wir elf Datenzeilen haben, die wir zurückgeben. In diesem Fall scheint es also nicht die effizienteste Art zu sein, Code zu schreiben.
Lassen Sie uns für einen anderen Ansatz eine Unterabfrage ausführen und so tun, als wäre es eine Tabelle:
Okay, wir haben also die gleichen Ergebnisse (etwas anders geordnet - anscheinend wollte die Datenbank Ergebnisse zurückgeben, die nach der ersten Spalte geordnet sind, die wir dieses Mal ausgewählt haben) - aber die gleichen richtigen Zahlen.
Was ist der Unterschied zwischen den beiden - und wann sollten wir jede Art von Unterabfrage verwenden? Stellen wir zunächst sicher, dass wir verstehen, wie diese zweite Abfrage funktioniert. Wir haben in der
from
Klausel unserer Abfrage zwei Tabellen ausgewählt , dann eine Abfrage geschrieben und der Datenbank mitgeteilt, dass es sich tatsächlich um eine Tabelle handelt - mit der die Datenbank vollkommen zufrieden ist. Die Verwendung dieser Methode kann einige Vorteile haben (sowie einige Einschränkungen). In erster Linie wurde diese Unterabfrage einmal ausgeführt . Wenn unsere Datenbank ein großes Datenvolumen enthalten würde, könnte es durchaus zu einer massiven Verbesserung gegenüber der ersten Methode kommen. Da wir dies jedoch als Tabelle verwenden, müssen wir zusätzliche Datenzeilen einbringen, damit diese tatsächlich wieder mit unseren Datenzeilen verknüpft werden können. Wir müssen auch sicher sein, dass es genug gibtDatenzeilen, wenn wir einen einfachen Join wie in der obigen Abfrage verwenden möchten. Wenn Sie sich erinnern, zieht der Join nur Zeilen zurück, die auf beiden Seiten des Joins übereinstimmende Daten enthalten . Wenn wir nicht vorsichtig sind, kann dies dazu führen, dass keine gültigen Daten aus unserer Autotabelle zurückgegeben werden, wenn diese Unterabfrage keine übereinstimmende Zeile enthält.Wenn wir nun auf die erste Unterabfrage zurückblicken, gibt es auch einige Einschränkungen. Da wir Daten in eine einzelne Zeile zurückziehen , können wir NUR eine Datenzeile zurückziehen. Unterabfragen in der verwendeten
select
Klausel einer Abfrage verwenden sehr oft nur eine Aggregatfunktion wiesum
,count
,max
oder eine andere ähnliche Aggregatfunktion. Sie haben nicht zu haben , aber das ist oft , wie sie geschrieben sind.Bevor wir fortfahren, werfen wir einen kurzen Blick darauf, wo wir sonst eine Unterabfrage verwenden können. Wir können es in der
where
Klausel verwenden - jetzt ist dieses Beispiel ein wenig erfunden, da es in unserer Datenbank bessere Möglichkeiten gibt, die folgenden Daten abzurufen, aber da es sich nur um ein Beispiel handelt, werfen wir einen Blick darauf:Dies gibt uns eine Liste von Marken-IDs und Markennamen zurück (die zweite Spalte wird nur hinzugefügt, um uns die Marken anzuzeigen), die den Buchstaben
o
im Namen enthalten.Jetzt können wir die Ergebnisse dieser Abfrage in einer where-Klausel verwenden:
Wie Sie sehen können, hatte unsere Autotabelle nur Einträge für zwei von ihnen, obwohl die Unterabfrage die drei Marken-IDs zurückgab.
In diesem Fall funktioniert die Unterabfrage für weitere Details so, als hätten wir den folgenden Code geschrieben:
Auch hier können Sie sehen, wie eine Unterabfrage im Vergleich zu manuellen Eingaben die Reihenfolge der Zeilen bei der Rückkehr aus der Datenbank geändert hat.
Lassen Sie uns sehen, was wir mit einer Unterabfrage noch tun können, während wir Unterabfragen diskutieren:
select
Klausel, einige in diefrom
Klausel und einige weitere in diewhere
Klausel. Denken Sie jedoch daran, dass jede von Ihnen eingegebene Abfrage Ihre Abfrage komplexer macht und wahrscheinlich länger dauert ausführen.Wenn Sie effizienten Code schreiben müssen, kann es hilfreich sein, die Abfrage auf verschiedene Arten zu schreiben und zu sehen (entweder durch Timing oder mithilfe eines Erklärungsplans), welche Abfrage optimal ist, um Ihre Ergebnisse zu erhalten. Der erste Weg, der funktioniert, ist möglicherweise nicht immer der beste Weg, dies zu tun.
quelle
Teil 3 - Tricks und effizienter Code
MySQL in () Effizienz
Ich dachte, ich würde ein paar zusätzliche Teile hinzufügen, um Tipps und Tricks zu erhalten.
Eine Frage, die ich ziemlich oft sehe, ist: Wie erhalte ich nicht übereinstimmende Zeilen aus zwei Tabellen und sehe die am häufigsten akzeptierte Antwort wie folgt (basierend auf unserer Tabelle mit Autos und Marken - in der Holden als aufgeführt ist Marke, erscheint aber nicht in der Autotabelle):
Und ja, es wird funktionieren.
In einigen Datenbanken ist es jedoch nicht effizient. Hier ist ein Link zu einer Frage zum Stapelüberlauf, die danach gefragt wird, und hier ist ein ausgezeichneter ausführlicher Artikel, wenn Sie sich mit dem Thema befassen möchten.
Die kurze Antwort lautet: Wenn der Optimierer nicht effizient damit umgeht, ist es möglicherweise viel besser, eine Abfrage wie die folgende zu verwenden, um nicht übereinstimmende Zeilen zu erhalten:
Aktualisieren Sie die Tabelle mit derselben Tabelle in der Unterabfrage
Ahhh, ein anderer Oldie, aber Goodie - der alte Sie können in der FROM-Klausel keine Zieltabellen -Marken für die Aktualisierung angeben .
Mit MySQL können Sie keine
update...
Abfrage mit einer Unterauswahl in derselben Tabelle ausführen . Nun denken Sie vielleicht, warum nicht einfach die where-Klausel richtig einfügen? Aber was ist, wenn Sie nur die Zeile mit demmax()
Datum unter einer Reihe anderer Zeilen aktualisieren möchten ? In einer where-Klausel können Sie das nicht genau tun.Also können wir das nicht machen, oder? Nun, nicht genau. Es gibt eine hinterhältige Problemumgehung, von der eine überraschend große Anzahl von Benutzern nichts weiß - obwohl sie einige Hackerangriffe enthält, auf die Sie achten müssen.
Sie können die Unterabfrage in eine andere Unterabfrage einfügen, wodurch eine ausreichende Lücke zwischen den beiden Abfragen entsteht, damit sie funktioniert. Beachten Sie jedoch, dass es möglicherweise am sichersten ist, die Abfrage innerhalb einer Transaktion zu speichern. Dadurch wird verhindert, dass andere Änderungen an den Tabellen vorgenommen werden, während die Abfrage ausgeführt wird.
quelle
Sie können das Konzept mehrerer Abfragen im Schlüsselwort FROM verwenden. Lassen Sie mich Ihnen ein Beispiel zeigen:
Sie können so viele Tabellen verwenden, wie Sie möchten. Verwenden Sie äußere Verknüpfungen und Vereinigungen, wo immer dies erforderlich ist, auch innerhalb von Tabellenunterabfragen.
Dies ist eine sehr einfache Methode, um so viele Tabellen und Felder einzubeziehen.
quelle
Hoffentlich findet es die Tabellen, während Sie die Sache durchlesen:
jsfiddle
quelle