Tous les jointures SQL dont vous aurez besoin
01 Oct 2018

Ben … peut-être pas tous. Mais avec ce cheatsheet, j’ai réussi cent pour cent des questions d’un examen universitaire sur les bases de données, donc j’imagine qu’il vaut quelque chose.
C’était un projet de trouver ce cheatsheet, parce que je n’avais pas même enregistré avec le mot “jointure” au nom du fichier. Je l’avais nommé “opérations ensemblistes en SQL”. Et c’est vraiment ce dont il s’agit. Il n’importe pas si l’on se sert du SQL, du VLOOKUP en Excel, du Python, ou d’un stylo et du papier pour comparer deux ensembles d’enregistrements. Combiner un ensemble de choses avec un autre est un problème mathématique. Mais c’est le calcul plaisant, pas le calcul difficile. On fait des diagrammes de Venn; c’es le genre de calcul qui vous permet de dessiner comme si vous étiez à l’école élémentaire.
Donné deux ensembles d’enregistrements (chaque “enregistrement” représente quelque chose dans la vie : une personne, une facture d’achat, une nation) éxistent dans un seul système de gestion de base de données relationnelle (SGBDR – on dit aussi tout simplement “base de données”), SQL est très utile. Tous ces systèmes offrent la possibilité d’extraire vos données à l’aide du langage de programmation SQL.
Je travaille principalement avec des bases de données Oracle, donc je peux composer la version de SQL “Oracle” plus vite que les autres et m’en servira pour les exemples de cet article. Vous pouvez exécuter du SQL Oracle en ligne avec un compte gratuit avec l’outil Live SQL.
Pour traduire les exemples vers une autre version du langage SQL, il va falloir peut-être Googler les mots clés à côté de votre système préféré. Par exemple, j’ai constaté que full outer join
ne marche pas avec les SGBD MySQL. Donc j’ai recherché “‘full outer join’ mysql” et j’ai découvert qu’une telle commande n’y est pas compris. Il faut combiner d’autres opérations habilement.
Les données d’exemple
Contenu du table “A
” (CONGRES
)
CONGRES
est une liste des participants à un congrès et de leurs lieux de travail.
(Oui, c’est un congrès très indiscret, demandant à ses participants un numéro d’identification national – le “ssn”.)
ssn | nom_prn | ph | em | company |
---|---|---|---|---|
A1A1A1 | Amjit, Anush | 1111111 | [email protected] | Apple |
B2B2B2 | Borges, Benita | 2222222 | [email protected] | Boiron |
C3C3C3 | Combs, Cathy | 3333333 | [email protected] | CVS |
D4D4D4 | Daher, Darweesh | 4444444 | [email protected] | Dell |
E5E5E5 | Ellis, Ezra | 5555555 | [email protected] | EDF |
F6F6F6 | Fulvia, Frances | 6666666 | [email protected] | Firestone |
Contenu du table “B
” (RESTAURANT
)
RESTAURANT
est une liste de clients habituels chez un restaurant, avec leur cuisine préféré et leur âge.
(Oui, c’est un restaurant très curieux qui demande à ses clients habituels un numéro d’identification national – le “social”.)
- Notez que l’adresse mail de Cathy Combs commence avec “ccc” et non “333”.
- Notez qu’il y a un erreur typographique dans le numéro d’identification national de Frances Fulvia.
social | prn_nom | phone | cuis_pref | age | |
---|---|---|---|---|---|
C3C3C3 | Cathy Combs | 3333333 | [email protected] | Carottes | 33 |
D4D4D4 | Darweesh Daher | 4444444 | [email protected] | Dattes | 44 |
E5E5E5 | Ezra Ellis | 5555555 | [email protected] | Endives | 55 |
FFF666 | Frances Fulvia | 6666666 | [email protected] | Frites | 66 |
G7G7G7 | Grace Gao | 7777777 | [email protected] | Gingembre | 77 |
H8H8H8 | Helen Hopper | 8888888 | [email protected] | Haricots | 88 |
Code pour créer les tables et inserer les données (“LDD” & “LMD”)
Voici du code pour créer les tables CONGRES
et RESTAURANT
dans une base de données Oracle et d’y enregistrer les données d’exemple, si vous voulez l’essayer.
Qui correspond à qui dans les données
Disons que nous sommes dans une grande entreprise. Une telle grande entreprise que l’on gère le congrès et que l’on possède le restaurant. On va chercher des correspondances entre les deux listes de clients.
A part de ça … je n’ai plus d’histoires pour expliquer les enquêtes qui vont suivre. Je créé les données et les enquêtes pour illustrer des idées logiques. Elles n’ont rien à voir avec la réalité.
Mais revenons à la combinaison de nos listes:
As always when comparing “people” records from two different data sets, decisions must be made about what “proves” two records represent the same “real-world person.” Do you match on name? Email? Social security number (remember, they are re-used after people die)? Some combination thereof?
For our examples, we’ll look at two different ways of combining our data, just to flex our code muscles.
Before reading the code, be sure to look at CONGRES
and RESTAURANT
and take note that:
- When we join on
A.ssn=B.social
, Cathy-Ezra (3-5) match- Anush, Benita, and “Frances w/
ssn
F6F6F6” remain unique toCONGRES
- “Frances w/
ssn
FFF666,” Grace, & Helen remain unique toRESTAURANT
- Anush, Benita, and “Frances w/
- When we join on
A.ph=B.phone and A.em=B.email
, Darweesh-Frances (4-6) match- Anush, Benita, and “Cathy w/
em
333@…” remain unique toCONGRES
- “Cathy w/
email
ccc@…,” Grace, & Helen remain unique toRESTAURANT
- Anush, Benita, and “Cathy w/
You’re fully debriefed! Let’s take a look at our first of 5 “join types.”
Join Type: “In A
”
For this join type, we’d expect 6 rows of output (Anush-Frances – all people from CONGRES
).
To the extent that any of these people “also exist” in RESTAURANT
(as defined by the “matching criteria” we choose), we’d expect to see details about them from RESTAURANT
.
LEFT OUTER JOIN
SQL Query, left outer join
example 1/4
First, we’ll match on social security number, so Cathy has details from “table B” but Frances doesn’t.
select A.nom_prn, A.company, B.prn_nom, B.cuis_pref
from CONGRES A
left outer join RESTAURANT B on A.ssn = B.social;
Query Output, left outer join
example 1/4
nom_prn | company | prn_nom | cuis_pref |
---|---|---|---|
Amjit, Anush | Apple | ||
Borges, Benita | Boiron | ||
Combs, Cathy | CVS | Cathy Combs | Carrots |
Daher, Darweesh | Dell | Darweesh Daher | Doritos |
Ellis, Ezra | EDF | Ezra Ellis | Endives |
Fulvia, Frances | Firestone |
SQL Query, left outer join
example 2/4
Next, we’ll match on phone and email, so Frances has details from “table B” but Cathy doesn’t.)
select A.nom_prn, A.company, B.prn_nom, B.cuis_pref
from CONGRES A
left outer join RESTAURANT B on A.ph = B.phone and A.em = B.email;
Query Output, left outer join
example 2/4
nom_prn | company | prn_nom | cuis_pref |
---|---|---|---|
Amjit, Anush | Apple | ||
Borges, Benita | Boiron | ||
Combs, Cathy | CVS | ||
Daher, Darweesh | Dell | Darweesh Daher | Doritos |
Ellis, Ezra | EDF | Ezra Ellis | Endives |
Fulvia, Frances | Firestone | Frances Fulvia | Fries |
SQL Query, left outer join
example 3/4
Next, we’ll try (incorrectly) to suppress prn_nom
and cuis_pref
details for anyone younger than 50.
select A.nom_prn, A.company, B.prn_nom, B.cuis_pref
from CONGRES A
left outer join RESTAURANT B on A.ssn = B.social
where B.age >= 50;
Query Output, left outer join
example 3/4
nom_prn | company | prn_nom | cuis_pref |
---|---|---|---|
Ellis, Ezra | EDF | Ezra Ellis | Endives |
Note
Even though “rows from B
” were optional in our join, in adding a filter on B
, we’ve effectively turned this “left join” into an “inner join” where our data must appear in both tables.
What we actually did was filter out the entire record of anyone who didn’t have an age (because they aren’t in table B
) or was younger than 50.
This is a common mistake. We’ll fix it in the next example.
In math, when you subtract numbers from each other, the order in which you subtract them matters.
Similarly, it’s important to think about the order in which you “join” and “filter” data as you solve your business problems with SQL.
SQL Query, left outer join
example 4/4
Now we’ll actually suppress prn_nom
and cuis_pref
details for anyone 50 or younger.
select A.nom_prn, A.company, B.prn_nom, B.cuis_pref
from CONGRES A
left outer join (select * from RESTAURANT where age >= 50) B on A.ssn = B.social;
Query Output, left outer join
example 4/4
nom_prn | company | prn_nom | cuis_pref |
---|---|---|---|
Amjit, Anush | Apple | ||
Borges, Benita | Boiron | ||
Combs, Cathy | CVS | ||
Daher, Darweesh | Dell | ||
Ellis, Ezra | EDF | Ezra Ellis | Endives |
Fulvia, Frances | Firestone |
Note
In our corrected query, we pre-filtered RESTAURANT
by age before treating it as B
, which fixed our problem from the previous example.
That was the first “join type.” Let’s take a look at the second.
Join Type: “In A
But Not In B
”
For this join type, we’d expect 3 rows of output (Anush+Benita+Cathy or Anush+Benita+Frances, depending on the “matching criteria” we choose).
Table B
is, by definition, not part of the final output from your business question, so remember that all of the approaches below will only include “details” from table A
.
NOT IN
SQL Query, not in
example 1/3
not in
is great when you’re only matching on one column.
select A.nom_prn, A.company
from CONGRES A
where A.ssn not in ( select B.social from RESTAURANT B );
Query Output, not in
example 1/3
nom_prn | company |
---|---|
Amjit, Anush | Apple |
Borges, Benita | Boiron |
Fulvia, Frances | Firestone |
SQL Query, not in
example 2/3
not in
gets dicey when you need to match on multiple columns – you have to concatenate multiple columns into a single column and responsibly handle blank/null values.
It is NOT PREFERRED for matching on multiple columns. Use NOT EXISTS
instead.
This query is just for show!
select A.nom_prn, A.company
from CONGRES A
where nvl(A.ph,'')||'~'||nvl(A.em,'') not in ( select nvl(B.phone,'')||'~'||nvl(B.email,'') from RESTAURANT B );
Query Output, not in
example 2/3
nom_prn | company |
---|---|
Amjit, Anush | Apple |
Borges, Benita | Boiron |
Combs, Cathy | CVS |
SQL Query, not in
example 3/3
Our third not in
example isn’t even a real join between tables: note that RESTAURANT
isn’t even in the query.
I just wanted to point out that this is typed the same way as the not in
that you can use when adding a hand-typed value filter to a query.
select A.nom_prn, A.company
from CONGRES A
where A.ssn not in ( 'B2B2B2','XYZZY','E5E5E5' );
Query Output, not in
example 3/3
nom_prn | company |
---|---|
Amjit, Anush | Apple |
Combs, Cathy | CVS |
Daher, Darweesh | Dell |
Fulvia, Frances | Firestone |
<> ALL
This is exactly like not in
, only you type <> all
instead. Every example from the section on not in
could have been written with <> all
.
SQL Query
select A.nom_prn, A.company
from CONGRES A
where A.ssn <> all ( select B.social from RESTAURANT B );
Query Output
nom_prn | company |
---|---|
Amjit, Anush | Apple |
Borges, Benita | Boiron |
Fulvia, Frances | Firestone |
MINUS
With minus
, we can’t output columns that aren’t in our “match criteria.”
That said, such limited output might suffice if our business problem is a simple “dummy check” list of “all values that appear only in A
.”
SQL Query, minus
example 1/2
select A.ssn
from CONGRES A
minus
select B.social
from RESTAURANT B;
Query Output, minus
example 1/2
ssn |
---|
A1A1A1 |
B2B2B2 |
F6F6F6 |
SQL Query, minus
example 2/2
select A.ph, A.em
from CONGRES A
minus
select B.phone, B.email
from RESTAURANT B;
Query Output, minus
example 2/2
ph | em |
---|---|
1111111 | [email protected] |
2222222 | [email protected] |
3333333 | [email protected] |
NOT EXISTS
USE THIS if you need to do “in A
, but not B
” with multi-column “matching criteria” in a complicated query!
where not exists (...)
is the most useful syntax for writing a complex query with “matching criteria” that involve a multi-column match.
This approach supports “further filters” on A
– just include them as additional and
and or
clauses beyond the where
clause responsible for the “matching” operation.
If the rest of your filters have or
in them, be sure to use parentheses to ensure that you don’t accidentally make your where not exists (...)
optional.
SQL Query
SELECT A.nom_prn, A.company
FROM CONGRES A
WHERE NOT EXISTS (
SELECT NULL
FROM RESTAURANT B
WHERE A.ph = B.phone and A.em = B.email
);
Query Output
nom_prn | company |
---|---|
Amjit, Anush | Apple |
Borges, Benita | Boiron |
Combs, Cathy | CVS |
LEFT OUTER JOIN ... B.... IS NULL
I can’t think of a single reason to use the “LEFT OUTER JOIN
plus B.joinColumn IS NULL
” syntax in practice. It’s completely overwrought.
But … it’s conceptually related to a common approach to “In A
Or B
, But Not Both” so it’s an interesting mental exercise to make sure you understand.
It’s also a good “cheat” pattern to be familiar with when you run into a report-writing tool that doesn’t have a NOT EXISTS
syntax, like Cognos Report Studio or Python+Pandas.
With this approach, it is vital to use the IS NULL
filter for all columns of B
that were involved in the LEFT OUTER JOIN
operation.
Otherwise, if your data set has a lot of NULL
values in it, you could get unexpected results.
This approach supports “further filters” on A
– just include them as additional and
and or
clauses beyond the where
clause responsible for the “matching” operation.
If the rest of your filters have or
in them, be sure to use parentheses to ensure that you don’t accidentally make your where ... is null
filter(s) optional.
SQL Query
select A.nom_prn, A.company
from CONGRES A
left outer join RESTAURANT B on A.ph = B.phone and A.em = B.email
where B.phone is null
and B.email is null;
Query Output
nom_prn | company |
---|---|
Amjit, Anush | Apple |
Borges, Benita | Boiron |
Combs, Cathy | CVS |
Congratulations getting through the second “join type.” On to the third!
Join Type: “In A
, B
, Or Both”
For this join type, we’d expect 9 rows of output (Anush-Helen, with Cathy or Frances doubled up depending on which “matching criteria” we choose).
UNION
SQL Query, union
example 1/2
select A.ssn
from CONGRES A
union
select B.social
from RESTAURANT B;
Query Output, union
example 1/2
ssn |
---|
A1A1A1 |
B2B2B2 |
C3C3C3 |
D4D4D4 |
E5E5E5 |
F6F6F6 |
FFF666 |
G7G7G7 |
H8H8H8 |
- Do you see the doubled-up “Frances” data?
Note
As with minus
, we can’t output columns that weren’t in our “match criteria.”
A single column of output might suffice if our business problem is a simple “dummy check” list of “all possible values from either table.”
SQL Query, union
example 2/2
select A.ph, A.em
from CONGRES A
union
select B.phone, B.email
from RESTAURANT B;
Query Output, union
example 2/2
ph | em |
---|---|
1111111 | [email protected] |
2222222 | [email protected] |
3333333 | [email protected] |
3333333 | [email protected] |
4444444 | [email protected] |
5555555 | [email protected] |
6666666 | [email protected] |
7777777 | [email protected] |
8888888 | [email protected] |
- Do you see the doubled-up “Cathy” data?
FULL OUTER JOIN
SQL Query, full outer join
example 1/2
select A.nom_prn, A.company, B.prn_nom, B.cuis_pref
from CONGRES A
full outer join RESTAURANT B on A.ssn = B.social;
Query Output, full outer join
example 1/2
nom_prn | company | prn_nom | cuis_pref |
---|---|---|---|
Amjit, Anush | Apple | ||
Borges, Benita | Boiron | ||
Combs, Cathy | CVS | Cathy Combs | Carrots |
Daher, Darweesh | Dell | Darweesh Daher | Doritos |
Ellis, Ezra | EDF | Ezra Ellis | Endives |
Fulvia, Frances | Firestone | ||
Frances Fulvia | Fries | ||
Grace Gao | Garlic | ||
Helen Hopper | Hummus |
- Do you see the doubled-up “Frances” data?
SQL Query, full outer join
example 2/2
select A.nom_prn, A.company, B.prn_nom, B.cuis_pref
from CONGRES A
full outer join RESTAURANT B on A.ph = B.phone and A.em = B.email;
Query Output, full outer join
example 2/2
nom_prn | company | prn_nom | cuis_pref |
---|---|---|---|
Amjit, Anush | Apple | ||
Borges, Benita | Boiron | ||
Combs, Cathy | CVS | ||
Daher, Darweesh | Dell | Darweesh Daher | Doritos |
Ellis, Ezra | EDF | Ezra Ellis | Endives |
Fulvia, Frances | Firestone | Frances Fulvia | Fries |
Cathy Combs | Carrots | ||
Grace Gao | Garlic | ||
Helen Hopper | Hummus |
- Do you see the doubled-up “Cathy” data?
MySQL fake FULL OUTER JOIN
This is the clever trickery I mentioned earlier to compensate for the fact that MySQL-flavored SQL doesn’t have a full outer join
command.
SQL Query
select A.nom_prn, A.company, B.prn_nom, B.cuis_pref
from CONGRES A
left outer join RESTAURANT B on A.ssn = B.social
union
select A.nom_prn, A.company, B.prn_nom, B.cuis_pref
from CONGRES A
right outer join RESTAURANT B on A.ssn = B.social;
Query Output
nom_prn | company | prn_nom | cuis_pref |
---|---|---|---|
Amjit, Anush | Apple | ||
Borges, Benita | Boiron | ||
Combs, Cathy | CVS | Cathy Combs | Carrots |
Daher, Darweesh | Dell | Darweesh Daher | Doritos |
Ellis, Ezra | EDF | Ezra Ellis | Endives |
Fulvia, Frances | Firestone | ||
Frances Fulvia | Fries | ||
Grace Gao | Garlic | ||
Helen Hopper | Hummus |
- Do you see the doubled-up “Frances” data?
Over halfway there! Keep reading to learn about the fourth “join type.”
This one has a lot of options, so it’ll be a bit of a longer read.
Join Type: “In Both A
And B
”
For this join type, we’d expect 3 rows of output (Cathy-Ezra or Darweesh-Frances, depending on the “matching criteria” we choose).
IN
SQL Query, in
example 1/3
select A.nom_prn, A.company
from CONGRES A
where A.ssn in ( select B.social from RESTAURANT B );
Query Output, in
example 1/3
nom_prn | company |
---|---|
Combs, Cathy | CVS |
Daher, Darweesh | Dell |
Ellis, Ezra | EDF |
Note
in
is great when:- you’re only matching on one column, and
- you don’t need to see, or filter further on, any details from
B
SQL Query, in
example 2/3
select A.nom_prn, A.company
from CONGRES A
where nvl(A.ph,'')||'~'||nvl(A.em,'') in ( select nvl(B.phone,'')||'~'||nvl(B.email,'') from RESTAURANT B );
Query Output, in
example 2/3
nom_prn | company |
---|---|
Daher, Darweesh | Dell |
Ellis, Ezra | EDF |
Fulvia, Frances | Firestone |
Note
in
gets dicey when you need to match on multiple columns – you have to concatenate multiple columns into a single column and responsibly handle blank/null values. It is NOT PREFERRED for matching on multiple columns. Useexists
instead. This is just for show!
SQL Query, in
example 3/3
select A.nom_prn, A.company
from CONGRES A
where A.ssn in ( 'B2B2B2','XYZZY','E5E5E5' );
Query Output, in
example 3/3
nom_prn | company |
---|---|
Borges, Benita | Boiron |
Ellis, Ezra | EDF |
Note
- This isn’t actually a real join between tables: note that
RESTAURANT
isn’t even in the query. I just wanted to point out that this is the samein
that you can use when adding a manual value filter to a query.
= ANY
SQL Query
select A.nom_prn, A.company
from CONGRES A
where A.ssn = any ( select B.social from RESTAURANT B );
Query Output
nom_prn | company |
---|---|
Combs, Cathy | CVS |
Daher, Darweesh | Dell |
Ellis, Ezra | EDF |
Note
This is exactly like in
, only you type = any
instead. All 3 examples from in
apply.
INTERSECT
SQL Query, intersect
example 1/2
select A.ssn
from CONGRES A
intersect
select B.social
from RESTAURANT B;
Query Output, intersect
example 1/2
ssn |
---|
C3C3C3 |
D4D4D4 |
E5E5E5 |
Note
As with minus
and union
, we can’t output columns that weren’t in our “match criteria.”
A single column of output might suffice if our business problem is a simple “dummy check” list of “all values that appear in both tables.”
SQL Query, intersect
example 2/2
select A.ph, A.em
from CONGRES A
intersect
select B.phone, B.email
from RESTAURANT B;
Query Output, intersect
example 2/2
ph | em |
---|---|
4444444 | [email protected] |
5555555 | [email protected] |
6666666 | [email protected] |
EXISTS
SQL Query
SELECT A.nom_prn, A.company
FROM CONGRES A
WHERE EXISTS (
SELECT NULL
FROM RESTAURANT B
WHERE A.ph = B.phone and A.em = B.email
);
Query Output
nom_prn | company |
---|---|
Daher, Darweesh | Dell |
Ellis, Ezra | EDF |
Fulvia, Frances | Firestone |
Note
exists
is better thanin
when your “matching criteria” involve multiple columns.- Like
in
,exists
doesn’t let you see, or further filter upon, details fromB
.
INNER JOIN
SQL Query
select A.nom_prn, A.company, B.prn_nom, B.cuis_pref
from CONGRES A
inner join RESTAURANT B on A.ph = B.phone and A.em = B.email;
Query Output
nom_prn | company | prn_nom | cuis_pref |
---|---|---|---|
Daher, Darweesh | Dell | Darweesh Daher | Doritos |
Ellis, Ezra | EDF | Ezra Ellis | Endives |
Fulvia, Frances | Firestone | Frances Fulvia | Fries |
=
The simple =
approach to joining tables is extraordinarily widespread and often taught first in tutorials to joining tables with SQL.
It supports “further filters” – just include them as additional and
and or
clauses beyond the where
clause responsible for the “matching” operation.
If the rest of your filters have or
in them, be sure to use parentheses to ensure that you don’t accidentally make your “join filter(s)” optional.
Avoiding such concerns is one reason I slightly prefer inner join
to the “=
” approach.
I almost always use explicit inner join
commands when I need to experiment to determine what query I want to write. It helps me avoid careless backspacing errors while I play.
SQL Query
select A.nom_prn, A.company, B.prn_nom, B.cuis_pref
from CONGRES A, RESTAURANT B
where A.ph = B.phone
and A.em = B.email;
Query Output
nom_prn | company | prn_nom | cuis_pref |
---|---|---|---|
Daher, Darweesh | Dell | Darweesh Daher | Doritos |
Ellis, Ezra | EDF | Ezra Ellis | Endives |
Fulvia, Frances | Firestone | Frances Fulvia | Fries |
So close you can taste it. One more to go – below is the fifth and final “join type.”
Join Type: “In A
Or B
, But Not Both”
For this join type, we’d expect 6 rows of output (Anush+Benita+Cathy1+Cathy2+Grace+Helen or Anush+Benita+Frances1+Frances2+Grace+Helen, depending on the “matching criteria” we choose).
There aren’t any SQL commands dedicated to this join type, but take a close look at the Venn diagram representing it. Can you see the “bite out of the middle” of what’s otherwise an “In A
, B
, Or Both” join? Your task is to write code that takes that “bite out of the middle.”
(Side note: it is very difficult to make this Venn diagram as a sugar cookie that won’t break when bringing treats for your Database 101 class’s final exam. Making it in SQL is much easier!)
Choose your own adventure
“Cut out the middle” of your overlapping circles by designing a query according to this architecture:
- Build an “In
A
,B
, Or Both” query using your favorite approach and think of it as your newA
. - Build an “In Both
A
AndB
” query using your favorite approach and think of it as your newB
. - Stitch together your new
A
and your newB
using your favorite “InA
But Not InB
” approach.
FULL OUTER JOIN ... A.... IS NULL OR B.... IS NULL
With this approach, it is vital to use the IS NULL
filter for all columns of A
and for all columns of B
that were involved in the FULL OUTER JOIN
operation.
Otherwise, if your data set has a lot of NULL
values in it, you could get unexpected results.
When you do this, “AND
” together filters on columns from the same table, but “OR
” together columns from different tables, as in the sample code below.
This approach supports “further filters” – just include them as additional and
and or
clauses beyond the where
clause(s) responsible for the “matching” operation.
Be sure to surround the entire ... or ...
filters responsible that “take a bite out of the middle” in their own set of parentheses, to avoid unexpected behavior.
If the rest of your filters have or
in them, use parentheses around them, too, to ensure that you don’t accidentally make your “bite out of the middle” filter optional.
SQL Query
select A.nom_prn, A.company, B.prn_nom, B.cuis_pref
from CONGRES A
full outer join RESTAURANT B on A.ph = B.phone and A.em = B.email
where
(
A.ph is null
and A.em is null
)
or
(
B.phone is null
and B.email is null
);
Query Output
nom_prn | company | prn_nom | cuis_pref |
---|---|---|---|
Amjit, Anush | Apple | ||
Borges, Benita | Boiron | ||
Combs, Cathy | CVS | ||
Cathy Combs | Carrots | ||
Grace Gao | Garlic | ||
Helen Hopper | Hummus |
You made it! Can you feel how much smarter you are yet?
More Resources
If you liked this post, other links that may interest you are:
- SQL Tutorials by Mode Analytics
- How to Make the Leap from Excel to SQL by Benn Stancil
- 4 Ways to Join Only The First Row in SQL by Periscope Data
- JOINs in SQL, Python, and R by Sadavath Sharma
- Python and SQL Overlap by David Wallace