Requête SQL renvoie des données à partir de plusieurs tables

j'aimerais savoir ce qui suit:

  • comment obtenir des données à partir de plusieurs tables dans ma base de données?
  • quels types de méthodes existe-t-il pour faire cela?
  • qu'est-ce que les jointures et les syndicats et en quoi sont-ils différents les uns des autres?
  • Quand dois-je utiliser chacun par rapport aux autres?

j'ai l'intention d'utiliser ceci dans Mon (par exemple - PHP) application, mais vous ne voulez pas exécuter des requêtes multiples contre la base de données, quelles options ai-je pour obtenir des données à partir de plusieurs tables dans une seule requête?

Note: j'écris ceci car je voudrais pouvoir faire un lien vers un guide bien écrit sur les nombreuses questions que je rencontre constamment dans la file D'attente PHP, donc je peux faire un lien vers ceci pour plus de détails lorsque je poste une réponse.

Les réponses couvrir ce qui suit:

  1. Partie 1-les adhésions et les syndicats
  2. Partie 2 - Les Sous-Requêtes
  3. Partie 3 - Trucs et Efficace du Code
  4. Partie 4 - les sous-requêtes dans la Clause from
  5. de la Partie 5 - Sac Mélangé de Jean Astuces
394
demandé sur Fluffeh 2012-09-18 15:11:39

6 réponses

Partie 1-les adhésions et les syndicats

cette réponse couvre:

  1. Partie 1
  2. partie 2
    • sous-séries-ce qu'elles sont, où elles peuvent être utilisées et ce qu'il faut faire attention
    • jointures cartésiennes AKA-Oh, la misère!

il existe plusieurs façons d'extraire des données de plusieurs tableaux d'une base de données. Dans cette réponse, j'utiliserai la syntaxe de jointure ANSI-92. Cela peut être différent d'un certain nombre d'autres tutoriels là-bas qui utilisent l'ancienne syntaxe ANSI-89 (et si vous êtes utilisé à 89, peut sembler beaucoup moins intuitif - mais tout ce que je peux dire est de l'essayer) car il est beaucoup plus facile à comprendre lorsque les requêtes commence à devenir plus complexe. Pourquoi l'utiliser? Y a-t-il un gain de performance? Le réponse courte est non, mais il est plus facile à lire une fois que vous vous y habituez. Il est plus facile de lire des requêtes écrites par d'autres personnes en utilisant cette syntaxe.

je vais également utiliser le concept d'une petite cour de triage qui dispose d'une base de données pour garder une trace des voitures disponibles. Le propriétaire vous a engagé comme son informaticien informatique et s'attend à ce que vous soyez en mesure de renoncer à lui les données qu'il demande à la baisse d'un chapeau.

j'ai fait un certain nombre de tables de recherche qui seront utilisées par la table finale. Cela nous donnera un modèle raisonnable à partir duquel travailler. Pour commencer, je vais lancer mes requêtes contre une base de données d'exemple qui a la structure suivante. Je vais essayer de penser aux erreurs courantes qui sont faites au début et expliquer ce qui va mal avec eux - ainsi que, bien sûr, montrer comment les corriger.

la première table est simplement une liste de couleurs afin que nous sachions quelles couleurs nous avons dans la Cour de la voiture.

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)

le tableau des marques identifie les différentes marques des voitures cour de triage pourrait éventuellement vendre.

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)

le tableau des modèles couvrira différents types de voitures, il va être plus simple pour cela d'utiliser différents types de voitures plutôt que des modèles de voitures réels.

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)

et enfin, attachez toutes les autres tables, la table qui lie tout ensemble. Le champ ID est en fait le numéro de lot unique utilisé pour identifier les voitures.

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)

cela nous donnera assez de données (je l'espère) pour couvrir les exemples ci-dessous de différents types de jointures et aussi donner assez de données pour les rendre utiles.

Afin d'entrer dans le sable, le patron veut savoir les Id de toutes Les voitures de sport qu'il a .

il s'agit d'une simple jointure de deux tables. Nous avons un tableau qui identifie le modèle et le tableau avec le stock disponible. Comme vous pouvez le voir, les données de la colonne model de la table cars se rapportent à la colonne models de la table cars que nous avons. Maintenant, nous savons que la table models A UN ID de 1 pour Sports donc permet d'écrire la jointure.

select
    ID,
    model
from
    cars
        join models
            on model=ID

donc cette requête semble bonne, n'est-ce pas? Nous avons identifiez les deux tables et contiennent l'information dont nous avons besoin et utilisez une jointure qui identifie correctement quelles colonnes joindre sur.

ERROR 1052 (23000): Column 'ID' in field list is ambiguous

Oh noes! Une erreur dans notre première requête! Oui, et c'est une prune. Vous voyez, la requête a en effet les bonnes colonnes, mais certaines d'entre elles existent dans les deux tables, donc la base de données est confuse sur ce que la colonne réelle nous voulons dire et où. Il y a deux solutions pour résoudre ce problème. La première est simple et agréable, nous pouvons utiliser tableName.columnName pour dites à la base de données exactement ce que nous voulons dire, comme ceci:

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)

l'autre est probablement le plus souvent utilisé et est appelé aliasing de table. Les tables dans cet exemple ont des noms simples et courts, mais taper quelque chose comme KPI_DAILY_SALES_BY_DEPARTMENT serait probablement vieillir rapidement, donc une manière simple est de donner un surnom à la table comme ceci:

select
    a.ID,
    b.model
from
    cars a
        join models b
            on a.model=b.ID

maintenant, retour à la demande. Comme vous pouvez le voir, nous avons l'information que nous avons besoin, mais nous avons aussi informations qui n'ont pas été demandées, nous devons donc inclure une clause où dans la déclaration pour obtenir seulement les voitures de sport comme demandé. Comme je préfère la méthode table alias plutôt que d'utiliser les noms de table encore et encore, je vais m'y tenir à partir de ce point.

clairement, nous devons ajouter une clause où à notre requête. Nous pouvons identifier les voitures de sport par ID=1 ou model='Sports' . Comme l'ID est indexé et la clé primaire (et il arrive à faire moins de frappe), permet d'utiliser que dans notre requête.

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! Le patron est heureux. Bien sûr, être un patron et de ne jamais être heureux avec ce qu'il a demandé, il regarde les informations, puis dit je veux des couleurs .

d'Accord, alors nous avons une bonne partie de notre requête déjà écrit, mais nous avons besoin d'une troisième table qui est en couleurs. Maintenant, notre principal tableau d'information cars stocke L'ID de couleur de la voiture et ce lien retour aux couleurs Colonne ID. Ainsi, de manière similaire à l'original, nous pouvons rejoindre une troisième table:

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)

Zut, bien que la table ait été correctement jointe et que les colonnes correspondantes aient été reliées, nous avons oublié de tirer le information de la nouvelle table que nous venons de relier.

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)

C'est ça, c'est le patron sur notre dos pour un moment. Maintenant, pour expliquer un peu plus en détail. Comme vous pouvez le voir, le from clause dans notre Énoncé lie notre table principale (j'utilise souvent une table qui contient des informations plutôt qu'une table de recherche ou de dimension. La requête fonctionnerait aussi bien avec les tables toutes interverties autour, mais faire moins de sens quand nous revenons à cette requête pour la lire dans quelques mois de temps, donc il est souvent préférable d'essayer d'écrire une requête qui sera agréable et facile à comprendre - l'exposer intuitivement, utiliser une belle indentation afin que tout soit aussi clair que cela peut l'être. Si vous allez sur enseignez aux autres, essayez d'instiller ces caractéristiques dans leurs requêtes - surtout si vous allez les dépanner.

il est tout à fait possible de relier de plus en plus de tableaux de cette manière.

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

Alors que j'ai oublié d'inclure une table où nous pourrions adhérer à plus d'une colonne dans le join , voici un exemple. Si la table models avait des modèles spécifiques à la marque et donc avait aussi une colonne appelée brand qui renvoie à la table brands sur le champ ID , il pourrait être fait comme ceci:

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

vous pouvez voir, la requête au-dessus non seulement lie les tables jointes à la table principale cars , mais spécifie aussi joins entre les tables déjà jointes. Si cela n'a pas été fait, le résultat est appelé une jointure cartésienne - qui est DBA parler pour le mauvais. Une jointure cartésienne est une jointure où les lignes sont retournées parce que l'information ne dit pas base de données comment limiter les résultats, de sorte que la requête retourne tous les lignes qui correspondent aux critères.

donc, pour donner un exemple de jointure cartésienne, lançons la requête suivante:

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)

Bon Dieu, c'est moche. Cependant, en ce qui concerne la base de données, c'est exactement ce qui a été demandé. Dans la requête, nous avons demandé le ID de cars et le model de models . Cependant, parce que nous n'avons pas spécifié comment pour rejoindre les tables, la base de données a apparié chaque "ligne 15191170920" de la première table avec chaque "ligne 15191170920" de la deuxième table.

Bon, le patron est de retour et il veut plus d'informations encore. je veux la même liste, mais aussi inclure 4WDs dans .

cela cependant, nous donne un grand excuse pour regarder deux façons différentes d'accomplir cela. Nous pourrions ajouter une autre condition à la clause où comme celle-ci:

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

alors que ce qui précède fonctionnera parfaitement, regardons-le différemment, c'est une excellente excuse pour montrer comment une requête union fonctionnera.

nous savons que les suivants retourneront toutes les voitures de sport:

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

et les suivants retourneraient tous les 4WDs:

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

ainsi, en ajoutant une clause union all entre eux, les résultats de la seconde requête seront annexés aux résultats de la première requête.

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)

Comme vous pouvez le voir, les résultats de la première requête est renvoyée en premier, suivi par les résultats de la deuxième requête.

dans cet exemple, il aurait été bien sûr beaucoup plus facile d'utiliser simplement la première requête, mais les requêtes union peuvent être excellentes pour des cas spécifiques. Ils sont un excellent moyen de retourner des résultats spécifiques de tableaux à partir de tableaux qui ne sont pas facilement réunis - ou d'ailleurs complètement tableaux non liés. Il y a cependant quelques règles à suivre.

  • les types de colonnes de la première requête doivent correspondre aux types de colonnes de toutes les autres requêtes ci-dessous.
  • Les noms des colonnes de la première requête sera utilisé pour identifier l'ensemble des résultats.
  • Le nombre de colonnes dans chaque requête doit être la même.

Maintenant, vous pourriez vous demandez ce que la différence est entre l'utilisation de union et union all . Une requête union supprimera les doublons, tandis qu'une requête union all ne le fera pas. Cela signifie qu'il y a un petit succès de performance lors de l'utilisation de union sur union all mais les résultats peuvent en valoir la peine - Je ne spéculerai pas sur ce genre de chose dans ceci cependant.

sur cette note, il pourrait être intéressant de noter quelques notes supplémentaires ici.

  • si nous voulions commander les résultats, nous pouvons utiliser un order by mais vous ne pouvez plus utiliser l'alias. Dans la requête ci-dessus, ajouter un order by a.ID entraînerait une erreur - en ce qui concerne les résultats, la colonne est appelée ID plutôt que a.ID - même si le même alias a été utilisé dans les deux requête.
  • nous ne pouvons avoir qu'une seule déclaration order by , et elle doit être la dernière.

pour les exemples suivants, j'ajoute quelques lignes supplémentaires à nos tableaux.

j'ai ajouté Holden au tableau des marques. J'ai aussi ajouté une ligne dans cars qui a la valeur color de 12 - qui n'a aucune référence dans la table de couleurs.

D'accord, le patron est encore une fois, aboyer demande dehors - * je veux un compte de chaque marque que nous portons et le nombre de voitures dans elle!"- Typiquement, nous arrivons juste à une section intéressante de notre discussion et le patron veut plus de travail.

Rightyo, donc la première chose que nous devons faire est d'obtenir une liste complète des marques possibles.

select
    a.brand
from
    brands a

+--------+
| brand  |
+--------+
| Ford   |
| Toyota |
| Nissan |
| Smart  |
| BMW    |
| Holden |
+--------+
6 rows in set (0.00 sec)

maintenant, quand nous joignons ceci à notre table de voitures nous obtenons le résultat suivant:

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)

Qui est bien sûr un problème - nous ne voyons aucune mention de la belle Holden marque j'ai ajouté.

c'est parce qu'une jointure cherche des lignes de correspondance dans les deux tableaux. Comme il n'y a pas de données dans les voitures de type Holden il n'est pas renvoyé. C'est là que nous pouvons utiliser une jointure outer . Ce sera retour tous les résultats d'un tableau, qu'ils soient appariés dans l'autre tableau ou non:

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)

maintenant que nous avons cela, nous pouvons ajouter une belle fonction agrégée pour obtenir un compte et obtenir le patron de nos dos pour un moment.

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)

et avec ça, plus de crânes de boss.

maintenant, pour expliquer cela plus en détail, les jointures externes peuvent être du type left ou right . La gauche ou la droite définit quel tableau est entièrement inclus. Un left outer join inclura toutes les lignes du tableau sur la gauche, tandis que (vous l'avez deviné) un right outer join apporte tous les résultats du tableau sur la droite dans les résultats.

certaines bases de données permettront un full outer join qui rapportera des résultats (appariés ou non) de les deux tables, mais ce n'est pas pris en charge dans toutes les bases de données.

maintenant, je suppose qu'à ce moment - ci, vous vous demandez si oui ou non vous pouvez fusionner les types join dans une requête - et le la réponse est oui, vous pouvez absolument.

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)

Alors, pourquoi n'est-ce pas les résultats escomptés? C'est parce que bien que nous ayons sélectionné la jointure extérieure des voitures aux marques, il n'a pas été précisé dans la jointure aux couleurs - de sorte que la jointure particulière ne fera revenir les résultats qui concordent dans les deux tableaux.

Voici la requête qui fonctionnerait pour obtenir les résultats que nous nous attendions:

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)

Comme nous pouvons le voir, nous avoir deux jointures externes dans la requête et les résultats viennent à travers comme prévu.

maintenant, Que diriez-vous de ces autres types de jointures que vous demandez? Et les Intersections?

bien, toutes les bases de données ne prennent pas en charge le intersection mais presque toutes les bases de données vous permettront de créer une intersection par une jointure (ou un énoncé bien structuré où au moins).

une Intersection est un type de jointure un peu similaire à un union comme décrit ci - dessus-mais la différence est que seulement renvoie des lignes de données qui sont identiques (et je veux dire identiques) entre les différentes requêtes individuelles rejointes par l'union. Seules les lignes identiques à tous égards seront retournées.

un exemple simple serait comme tel:

select
    *
from
    colors
where
    ID>2
intersect
select
    *
from
    colors
where
    id<4

alors qu'une requête normale union retournerait toutes les lignes de la table (la première requête en retournant tout ce qui dépasse ID>2 et le second Tout ce qui a ID<4 ) ce qui donnerait un jeu complet, une requête intersect retournerait seulement la ligne correspondant à id=3 car il répond aux deux critères.

maintenant, si votre base de données ne supporte pas une requête intersect , la requête ci-dessus peut être facilement complétée avec la requête suivante:

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)

si vous souhaitez effectuer une intersection entre deux tables différentes en utilisant une base de données cela ne supporte pas en soi une requête d'intersection, vous aurez besoin de créer une jointure sur chaque colonne des tables.

411
répondu Fluffeh 2017-05-23 12:26:38

Ok, j'ai trouvé ce post très intéressant et je voudrais partager certaines de mes connaissances sur la création d'une requête. Merci pour ce Fluffeh . D'autres qui peuvent lire ceci et peuvent penser que je me trompe sont libres à 101% de modifier et de critiquer ma réponse. ( honnêtement, je me sens très reconnaissant d'avoir corrigé mes erreurs. )

je vais poster quelques-unes des questions les plus fréquemment posées dans MySQL balise.


astuce n ° 1 ( lignes qui correspondent à des conditions multiples )

vu ce schéma

CREATE TABLE MovieList
(
    ID INT,
    MovieName VARCHAR(25),
    CONSTRAINT ml_pk PRIMARY KEY (ID),
    CONSTRAINT ml_uq UNIQUE (MovieName)
);

INSERT INTO MovieList VALUES (1, 'American Pie');
INSERT INTO MovieList VALUES (2, 'The Notebook');
INSERT INTO MovieList VALUES (3, 'Discovery Channel: Africa');
INSERT INTO MovieList VALUES (4, 'Mr. Bean');
INSERT INTO MovieList VALUES (5, 'Expendables 2');

CREATE TABLE CategoryList
(
    MovieID INT,
    CategoryName VARCHAR(25),
    CONSTRAINT cl_uq UNIQUE(MovieID, CategoryName),
    CONSTRAINT cl_fk FOREIGN KEY (MovieID) REFERENCES MovieList(ID)
);

INSERT INTO CategoryList VALUES (1, 'Comedy');
INSERT INTO CategoryList VALUES (1, 'Romance');
INSERT INTO CategoryList VALUES (2, 'Romance');
INSERT INTO CategoryList VALUES (2, 'Drama');
INSERT INTO CategoryList VALUES (3, 'Documentary');
INSERT INTO CategoryList VALUES (4, 'Comedy');
INSERT INTO CategoryList VALUES (5, 'Comedy');
INSERT INTO CategoryList VALUES (5, 'Action');

QUESTION

trouver tous les films qui appartiennent au moins à la fois Comedy et Romance catégories.

Solution

cette question peut parfois être très délicate. Il peut sembler qu'une requête de ce sera la réponse:-

SELECT  DISTINCT a.MovieName
FROM    MovieList a
        INNER JOIN CategoryList b
            ON a.ID = b.MovieID
WHERE   b.CategoryName = 'Comedy' AND
        b.CategoryName = 'Romance'

SQLFiddle Demo

ce qui est certainement très mal parce qu'il produit pas de résultat . L'explication de ceci est qu'il existe une seule valeur valide de CategoryName sur chaque ligne . Par exemple, la première condition renvoie vrai , la deuxième condition est toujours fausse. Ainsi, en utilisant l'opérateur AND , les deux conditions doivent être vraies; sinon, elles seront fausses. Une autre requête est comme ceci,

SELECT  DISTINCT a.MovieName
FROM    MovieList a
        INNER JOIN CategoryList b
            ON a.ID = b.MovieID
WHERE   b.CategoryName IN ('Comedy','Romance')

SQLFiddle Demo

et le résultat est encore incorrect parce qu'il correspond à l'enregistrement qui a au moins un match sur le categoryName . La réelle solution serait en comptant le nombre d'instances d'enregistrement par film . Le nombre d'instance doit correspondre au nombre total de valeurs fournies en l'état.

SELECT  a.MovieName
FROM    MovieList a
        INNER JOIN CategoryList b
            ON a.ID = b.MovieID
WHERE   b.CategoryName IN ('Comedy','Romance')
GROUP BY a.MovieName
HAVING COUNT(*) = 2

SQLFiddle Démo (la réponse)


truc n ° 2 ( enregistrement maximum pour chaque entrée )

schéma donné,

CREATE TABLE Software
(
    ID INT,
    SoftwareName VARCHAR(25),
    Descriptions VARCHAR(150),
    CONSTRAINT sw_pk PRIMARY KEY (ID),
    CONSTRAINT sw_uq UNIQUE (SoftwareName)  
);

INSERT INTO Software VALUES (1,'PaintMe','used for photo editing');
INSERT INTO Software VALUES (2,'World Map','contains map of different places of the world');
INSERT INTO Software VALUES (3,'Dictionary','contains description, synonym, antonym of the words');

CREATE TABLE VersionList
(
    SoftwareID INT,
    VersionNo INT,
    DateReleased DATE,
    CONSTRAINT sw_uq UNIQUE (SoftwareID, VersionNo),
    CONSTRAINT sw_fk FOREIGN KEY (SOftwareID) REFERENCES Software(ID)
);

INSERT INTO VersionList VALUES (3, 2, '2009-12-01');
INSERT INTO VersionList VALUES (3, 1, '2009-11-01');
INSERT INTO VersionList VALUES (3, 3, '2010-01-01');
INSERT INTO VersionList VALUES (2, 2, '2010-12-01');
INSERT INTO VersionList VALUES (2, 1, '2009-12-01');
INSERT INTO VersionList VALUES (1, 3, '2011-12-01');
INSERT INTO VersionList VALUES (1, 2, '2010-12-01');
INSERT INTO VersionList VALUES (1, 1, '2009-12-01');
INSERT INTO VersionList VALUES (1, 4, '2012-12-01');

QUESTION

trouvez la dernière version de chaque logiciel. Afficher les colonnes suivantes: SoftwareName , Descriptions , LatestVersion ( de la colonne VersionNo ), DateReleased

Solution

certains développeurs SQL utilisent par erreur MAX() fonction agrégée. Ils ont tendance à créer comme ceci,

SELECT  a.SoftwareName, a.Descriptions,
        MAX(b.VersionNo) AS LatestVersion, b.DateReleased
FROM    Software a
        INNER JOIN VersionList b
            ON a.ID = b.SoftwareID
GROUP BY a.ID
ORDER BY a.ID

SQLFiddle Demo

( la plupart des SGBDR génère une erreur de syntaxe sur ce parce que de ne pas spécifier certains de la non-agrégées colonnes sur la group by clause ) le résultat produit correct LatestVersion chaque logiciel mais évidemment le DateReleased sont incorrects. MySQL ne supporte pas Window Functions et Common Table Expression pourtant comme certains RDBMS le font déjà. La solution à ce problème est de créer un subquery qui obtient le maximum individuel versionNo sur chaque logiciel et plus tard être joint sur les autres tables.

SELECT  a.SoftwareName, a.Descriptions,
        b.LatestVersion, c.DateReleased
FROM    Software a
        INNER JOIN
        (
            SELECT  SoftwareID, MAX(VersionNO) LatestVersion
            FROM    VersionList
            GROUP BY SoftwareID
        ) b ON a.ID = b.SoftwareID
        INNER JOIN VersionList c
            ON  c.SoftwareID = b.SoftwareID AND
                c.VersionNO = b.LatestVersion
GROUP BY a.ID
ORDER BY a.ID

SQLFiddle Démo (la réponse)


donc c'était il. Je vais poster un autre dès que je me souviens de n'importe quel autre FAQ sur MySQL étiquette. Je vous remercie pour la lecture de ce petit article. J'espère que vous en avez au moins un peu appris.

UPDATE 1


astuce No 3 ( trouver le dernier record entre deux IDs )

Schéma Donné

CREATE TABLE userList
(
    ID INT,
    NAME VARCHAR(20),
    CONSTRAINT us_pk PRIMARY KEY (ID),
    CONSTRAINT us_uq UNIQUE (NAME)  
);

INSERT INTO userList VALUES (1, 'Fluffeh');
INSERT INTO userList VALUES (2, 'John Woo');
INSERT INTO userList VALUES (3, 'hims056');

CREATE TABLE CONVERSATION
(
    ID INT,
    FROM_ID INT,
    TO_ID INT,
    MESSAGE VARCHAR(250),
    DeliveryDate DATE
);

INSERT INTO CONVERSATION VALUES (1, 1, 2, 'hi john', '2012-01-01');
INSERT INTO CONVERSATION VALUES (2, 2, 1, 'hello fluff', '2012-01-02');
INSERT INTO CONVERSATION VALUES (3, 1, 3, 'hey hims', '2012-01-03');
INSERT INTO CONVERSATION VALUES (4, 1, 3, 'please reply', '2012-01-04');
INSERT INTO CONVERSATION VALUES (5, 3, 1, 'how are you?', '2012-01-05');
INSERT INTO CONVERSATION VALUES (6, 3, 2, 'sample message!', '2012-01-05');

QUESTION

Trouver la dernière conversation entre deux utilisateurs.

Solution

SELECT    b.Name SenderName,
          c.Name RecipientName,
          a.Message,
          a.DeliveryDate
FROM      Conversation a
          INNER JOIN userList b
            ON a.From_ID = b.ID
          INNER JOIN userList c
            ON a.To_ID = c.ID
WHERE     (LEAST(a.FROM_ID, a.TO_ID), GREATEST(a.FROM_ID, a.TO_ID), DeliveryDate)
IN
(
    SELECT  LEAST(FROM_ID, TO_ID) minFROM,
            GREATEST(FROM_ID, TO_ID) maxTo,
            MAX(DeliveryDate) maxDate
    FROM    Conversation
    GROUP BY minFROM, maxTo
)

SQLFiddle Demo

94
répondu John Woo 2017-05-23 12:26:38

Partie 2 - Les Sous-Requêtes

Ok, maintenant le patron a encore fait irruption - je veux une liste de toutes nos voitures avec la marque et un total de combien de cette marque nous avons!

c'est une excellente occasion d'utiliser le prochain tour dans notre sac de goodies SQL - le sous-jeu. Si vous n'êtes pas familier avec le terme, un sous-jeu est une requête qui court à l'intérieur d'une autre requête. Il existe de nombreuses façons de les utiliser.

pour notre demande, mettons d'abord une requête simple ensemble qui énumérera chaque voiture et la marque:

select
    a.ID,
    b.brand
from
    cars a
        join brands b
            on a.brand=b.ID

Maintenant, si nous voulions simplement obtenir un nombre de wagons triés par marque, on peut bien sûr écrire ceci:

select
    b.brand,
    count(a.ID) as countCars
from
    cars a
        join brands b
            on a.brand=b.ID
group by
    b.brand

+--------+-----------+
| brand  | countCars |
+--------+-----------+
| BMW    |         2 |
| Ford   |         2 |
| Nissan |         1 |
| Smart  |         1 |
| Toyota |         5 |
+--------+-----------+

donc, nous devrions être en mesure d'ajouter simplement la fonction count à notre requête d'origine n'est-ce pas?

select
    a.ID,
    b.brand,
    count(a.ID) as countCars
from
    cars a
        join brands b
            on a.brand=b.ID
group by
    a.ID,
    b.brand

+----+--------+-----------+
| ID | brand  | countCars |
+----+--------+-----------+
|  1 | Toyota |         1 |
|  2 | Ford   |         1 |
|  3 | Nissan |         1 |
|  4 | Smart  |         1 |
|  5 | Toyota |         1 |
|  6 | BMW    |         1 |
|  7 | Ford   |         1 |
|  8 | Toyota |         1 |
|  9 | Toyota |         1 |
| 10 | BMW    |         1 |
| 11 | Toyota |         1 |
+----+--------+-----------+
11 rows in set (0.00 sec)

malheureusement, non, on ne peut pas faire ça. La raison en est que lorsque nous ajoutons L'ID de la voiture (colonne A. ID) nous devons l'ajouter dans le groupe by - donc maintenant, quand la fonction count fonctionne, il n'y a qu'un seul ID par ID.

C'est là que nous pouvons cependant utiliser un sous - jeu-en fait nous pouvons faire deux types complètement différents de sous-jeu qui retourneront les mêmes résultats que nous avons besoin pour cela. La première consiste simplement à placer la sous-requête dans la clause select . Cela signifie que chaque fois que nous obtenons une rangée de données, le sous-jeu s'exécute, obtenir une colonne de données et puis pop dans notre ligne de données.

select
    a.ID,
    b.brand,
    (
    select
        count(c.ID)
    from
        cars c
    where
        a.brand=c.brand
    ) as countCars
from
    cars a
        join brands b
            on a.brand=b.ID

+----+--------+-----------+
| ID | brand  | countCars |
+----+--------+-----------+
|  2 | Ford   |         2 |
|  7 | Ford   |         2 |
|  1 | Toyota |         5 |
|  5 | Toyota |         5 |
|  8 | Toyota |         5 |
|  9 | Toyota |         5 |
| 11 | Toyota |         5 |
|  3 | Nissan |         1 |
|  4 | Smart  |         1 |
|  6 | BMW    |         2 |
| 10 | BMW    |         2 |
+----+--------+-----------+
11 rows in set (0.00 sec)

Et Bam! ce serait faire de nous. Si vous avez remarqué, cette requête secondaire devra être exécutée pour chaque ligne de données que nous retournons. Même dans ce petit exemple, nous n'avons que cinq marques différentes de voiture, mais la sous-série a couru onze fois que nous avons onze rangées de données que nous retournons. Donc, dans ce cas, ça ne semble pas être la façon la plus efficace d'écrire du code.

pour une approche différente, lançons un subquery et prétendre qu'il est une table:

select
    a.ID,
    b.brand,
    d.countCars
from
    cars a
        join brands b
            on a.brand=b.ID
        join
            (
            select
                c.brand,
                count(c.ID) as countCars
            from
                cars c
            group by
                c.brand
            ) d
            on a.brand=d.brand

+----+--------+-----------+
| ID | brand  | countCars |
+----+--------+-----------+
|  1 | Toyota |         5 |
|  2 | Ford   |         2 |
|  3 | Nissan |         1 |
|  4 | Smart  |         1 |
|  5 | Toyota |         5 |
|  6 | BMW    |         2 |
|  7 | Ford   |         2 |
|  8 | Toyota |         5 |
|  9 | Toyota |         5 |
| 10 | BMW    |         2 |
| 11 | Toyota |         5 |
+----+--------+-----------+
11 rows in set (0.00 sec)

D'accord, donc nous avons les mêmes résultats (ordonnés légèrement différents - il semble que la base de données voulait retourner les résultats ordonnés par la première colonne que nous avons choisie cette fois - ci) - mais les mêmes nombres droits.

alors, quelle est la différence entre les deux - et quand devrions-nous utiliser chaque type de sous-marin? Tout d'abord, assurons-nous de comprendre comment fonctionne la seconde requête. Nous avons sélectionné deux tableaux dans le from clause de notre requête, puis a écrit une requête et a dit à la base de données qu'il était en fait une table à la place - qui la base de données est parfaitement heureux avec. Il peut être certains avantages à utiliser cette méthode (ainsi que certaines limites). Le plus important est que ce sous-query a couru une fois . Si notre base de données contenait un grand volume de données, il pourrait bien y avoir une amélioration massive par rapport à la première méthode. Cependant, comme nous l'utilisons comme un tableau, nous devons apporter dans les rangées supplémentaires de données - de sorte qu'ils puissent être effectivement joints à nos rangées de données. Nous devons également être sûrs qu'il ya assez lignes de données si nous allons utiliser une jointure simple comme dans la requête ci-dessus. Si vous vous souvenez, la jointure ne tirera en arrière les lignes qui ont des données correspondantes sur les deux côtés de la jointure. Si nous ne faisons pas attention, cela pourrait entraîner des données valides n'étant pas retournés de notre table de voitures s'il n'y avait pas une rangée correspondante dans ce sous-requête.

maintenant, en regardant en arrière au premier sous-jeu, il y a aussi quelques limites. parce que nous ramenons des données dans une seule rangée, nous pouvons seulement tirer en arrière une rangée de données. Les sous-séries utilisées dans la clause select d'une requête utilisent très souvent seulement une fonction agrégée telle que sum , count , max ou une autre fonction agrégée similaire. Ils ne ont à, mais c'est souvent comment ils sont écrits.

donc, avant de passer à autre chose, jetons un coup d'oeil rapide à l'endroit où nous pouvons utiliser un sous-jeu. On peut l'utiliser dans la where clause - maintenant, cet exemple est un peu artificiel, comme dans notre base de données, il existe de meilleures façons d'obtenir les données suivantes, mais vu que c'est seulement un exemple, permet d'avoir un regard:

select
    ID,
    brand
from
    brands
where
    brand like '%o%'

+----+--------+
| ID | brand  |
+----+--------+
|  1 | Ford   |
|  2 | Toyota |
|  6 | Holden |
+----+--------+
3 rows in set (0.00 sec)

ceci nous renvoie une liste d'identificateurs de marque et de noms de marque (la deuxième colonne n'est ajoutée que pour nous montrer les marques) qui contiennent la lettre o dans le nom.

maintenant, nous pourrions utiliser les résultats de cette requête dans une clause où ceci:

select
    a.ID,
    b.brand
from
    cars a
        join brands b
            on a.brand=b.ID
where
    a.brand in
        (
        select
            ID
        from
            brands
        where
            brand like '%o%'
        )

+----+--------+
| ID | brand  |
+----+--------+
|  2 | Ford   |
|  7 | Ford   |
|  1 | Toyota |
|  5 | Toyota |
|  8 | Toyota |
|  9 | Toyota |
| 11 | Toyota |
+----+--------+
7 rows in set (0.00 sec)

comme vous pouvez le voir, même si le sous-magasin retournait les trois identifiants de la marque, notre table de voitures n'avait des entrées que pour deux d'entre eux.

dans ce cas, pour plus de détails, le sous-jeu fonctionne comme si nous écrivions le code suivant:

select
    a.ID,
    b.brand
from
    cars a
        join brands b
            on a.brand=b.ID
where
    a.brand in (1,2,6)

+----+--------+
| ID | brand  |
+----+--------+
|  1 | Toyota |
|  2 | Ford   |
|  5 | Toyota |
|  7 | Ford   |
|  8 | Toyota |
|  9 | Toyota |
| 11 | Toyota |
+----+--------+
7 rows in set (0.00 sec)

encore une fois, vous pouvez voir comment un sous-jeu vs entrées manuelles a changé l'ordre des lignes en revenant de la base de données.

pendant que nous discutons des sous-commandes, voyons ce que nous pouvons faire d'autre avec une sous-commande:

  • vous pouvez placer un sous-jeu dans un autre sous-jeu, et ainsi de suite. Il y a une limite qui dépend de votre base de données, mais à moins de fonctions récursives d'un programmeur fou et maniaque, la plupart des gens ne toucheront jamais cette limite.
  • vous pouvez placer un certain nombre de sous - séries dans une seule requête, quelques-unes dans la clause select , quelques-unes dans la clause from et un couple plus dans la clause where - juste se rappeler que chacun que vous mettez en rend votre requête plus complexe et susceptible de prendre plus de temps à exécuter.

si vous avez besoin d'écrire un code efficace, il peut être bénéfique d'écrire la requête un certain nombre de façons Et Voir (soit en la chronométrant ou en utilisant un expliquer plan) qui est la requête optimale pour obtenir vos résultats. La première façon qui fonctionne peut ne pas toujours être la meilleure façon de le faire.

59
répondu Fluffeh 2012-09-19 09:47:16

Partie 3 - Trucs et Efficace du Code

MySQL() de l'efficacité

j'ai pensé que je voudrais ajouter certains des bits supplémentaires, des conseils et astuces.

une question que je vois venir un peu, est Comment puis-je obtenir des lignes non-appariées à partir de deux tableaux et je vois la réponse la plus communément acceptée comme quelque chose comme ce qui suit (basé sur nos voitures et marques de table-qui a Holden inscrit comme marque, mais ne figure pas dans le tableau cars):

select
    a.ID,
    a.brand
from
    brands a
where
    a.ID not in(select brand from cars)

Et oui il va travailler.

+----+--------+
| ID | brand  |
+----+--------+
|  6 | Holden |
+----+--------+
1 row in set (0.00 sec)

mais il est pas efficace dans une base de données. Voici un lien à une question de débordement de la pile poser à ce sujet, et voici un excellent en profondeur article si vous voulez entrer dans la gravitation nitty.

la réponse courte est, si l'optimiseur ne le gère pas efficacement, il peut être beaucoup mieux d'utiliser une requête comme la suivante pour obtenir des lignes non appariées:

select
    a.brand
from
    brands a
        left join cars b
            on a.id=b.brand
where
    b.brand is null

+--------+
| brand  |
+--------+
| Holden |
+--------+
1 row in set (0.00 sec)

mettre à Jour le Tableau avec la même table dans la sous-requête

Ahhh, un autre ancien mais goodie - l'ancien Vous ne pouvez pas spécifier une table cible 'marques' pour la mise à jour DE la clause .

MySQL ne vous permettra pas d'exécuter un update... requête avec un sous-Select sur la même table. Maintenant, vous pourriez penser, pourquoi ne pas simplement le mettre dans la clause où il faut? Mais que faire si vous voulez mettre à jour seulement la ligne avec la date max() parmi un tas d'autres lignes? On ne peut pas faire ça dans une clause "où".

update 
    brands 
set 
    brand='Holden' 
where 
    id=
        (select 
            id 
        from 
            brands 
        where 
            id=6);
ERROR 1093 (HY000): You can't specify target table 'brands' 
for update in FROM clause

donc, on ne peut pas faire ça hein? Eh bien, pas exactement. Il ya un contournement sournois qu'un nombre étonnamment grand d'utilisateurs ne savent pas-bien qu'il ne comprend certains hackery que vous aurez besoin de prêter attention à.

vous pouvez coller le sous-jeu dans un autre sous-jeu, ce qui met assez d'espace entre les deux requêtes pour qu'il fonctionne. Cependant, notez qu'il peut être plus sûr de coller la requête dans une transaction - cela empêchera tout autre changement étant fait aux tables pendant que la requête est en cours d'exécution.

update 
    brands 
set 
    brand='Holden' 
where id=
    (select 
        id 
    from 
        (select 
            id 
        from 
            brands 
        where 
            id=6
        ) 
    as updateTable);

Query OK, 0 rows affected (0.02 sec)
Rows matched: 1  Changed: 0  Warnings: 0
55
répondu Fluffeh 2017-05-23 11:47:32

vous pouvez utiliser le concept de requêtes multiples dans le mot-clé de FROM. Laissez-moi vous montrer un exemple:

SELECT DISTINCT e.id,e.name,d.name,lap.lappy LAPTOP_MAKE,c_loc.cnty COUNTY    
FROM  (
          SELECT c.id cnty,l.name
          FROM   county c, location l
          WHERE  c.id=l.county_id AND l.end_Date IS NOT NULL
      ) c_loc, emp e 
      INNER JOIN dept d ON e.deptno =d.id
      LEFT JOIN 
      ( 
         SELECT l.id lappy, c.name cmpy
         FROM   laptop l, company c
         WHERE l.make = c.name
      ) lap ON e.cmpy_id=lap.cmpy

Vous pouvez utiliser autant de tables que vous voulez. Utilisez les joints extérieurs et l'union où jamais il est nécessaire, même à l'intérieur des sous-séries de table.

C'est une méthode très facile d'impliquer autant de tables et de champs.

16
répondu prashant1988 2012-09-27 04:27:04

espère que cela lui permet de trouver les tables que vous lisez à travers la chose:

jsfiddle

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    |                |
+-------+-------------+------+-----+---------+----------------+
5
répondu Anton Chan 2016-05-19 09:33:40