web-dev-qa-db-fra.com

SQL - Comment retourner des lignes de la table de gauche non trouvées dans la table de droite?

J'ai deux tables avec des noms de colonne similaires et je dois renvoyer des enregistrements de la table de gauche qui ne se trouvent pas dans la table de droite? J'ai une clé primaire (colonne) qui m'aidera à comparer les deux tableaux. Quelle jointure est préférée?

35
CloudJedi

Si vous demandez T-SQL, examinons d’abord les principes fondamentaux. Il existe trois types de jointures, chacune avec son propre ensemble de phases de traitement logique, à savoir:

  1. Un cross join est le plus simple de tous. Il implémente une seule phase de traitement de requête logique, un Cartesian Product. Cette phase fonctionne sur les deux tables fournies en entrée de la jointure et produit un produit cartésien des deux. C'est-à-dire que chaque ligne d'une entrée correspond à toutes les lignes de l'autre. Ainsi, si vous avez m lignes dans une table et n lignes dans l’autre, vous obtenez m × n lignes dans le résultat.
  2. Inner joins: Ils appliquent deux phases de traitement de requête logique: A Cartesian product entre les deux tables d'entrée comme dans une jointure croisée, puis filters lignes en fonction d'un prédicat que vous spécifiez dans la clause ON (également appelé Join condition).
  3. Vient ensuite le troisième type de jointure, Outer Joins:

    Dans un outer join, vous marquez une table en tant que table preserved en utilisant les mots-clés LEFT OUTER JOIN, RIGHT OUTER JOIN ou FULL OUTER JOIN entre les noms de table. Le mot clé OUTER est optional. Le mot clé LEFT signifie que les lignes du left table sont préservées; le mot clé RIGHT signifie que les lignes du right table sont préservées; et le mot clé FULL signifie que les lignes des tables both et left et right sont préservées.

    La troisième phase de traitement d'une requête logique d'un outer join identifie les lignes de la table préservée qui ne trouvaient pas de correspondances dans l'autre table en fonction du prédicat ON. Cette phase ajoute ces lignes à la table de résultats générée par les deux premières phases de la jointure et utilise les marques NULL comme espaces réservés pour les attributs du côté non préservé de la jointure dans ces lignes externes.

Examinons maintenant la question suivante: Pour renvoyer les enregistrements de la table de gauche qui ne se trouvent pas dans la table de droite, utilisez Left outer join et filtrez les lignes avec les valeurs NULL pour les attributs du côté droit de la jointure.

32
Deepshikha

Essaye ça

SELECT f.*
FROM first_table f LEFT JOIN second_table s ON f.key=s.key
WHERE s.key is NULL

Pour plus d’informations, consultez cet article: Jointures dans Sql Server

 enter image description here

44
Shamseer K

J'aime aussi utiliser NOT EXISTS. Quand il s’agit de la performance, si l’index est correct, il devrait fonctionner comme un LEFT JOIN ou meilleur. De plus, il est plus facile à lire.

SELECT Column1
FROM TableA a
WHERE NOT EXISTS ( SELECT Column1
                   FROM Tableb b
                   WHERE a.Column1 = b.Column1
                 )
4
viejoEngineer

Je ne peux rien ajouter d'autre qu'un exemple de code aux deux autres réponses: cependant, je trouve qu'il peut être utile de le voir en action (les autres réponses, à mon avis, sont meilleures parce qu'elles l'expliquent). 

DECLARE @testLeft TABLE (ID INT, SomeValue VARCHAR(1))
DECLARE @testRight TABLE (ID INT, SomeOtherValue VARCHAR(1))

INSERT INTO @testLeft (ID, SomeValue) VALUES (1, 'A')
INSERT INTO @testLeft (ID, SomeValue) VALUES (2, 'B')
INSERT INTO @testLeft (ID, SomeValue) VALUES (3, 'C')


INSERT INTO @testRight (ID, SomeOtherValue) VALUES (1, 'X')
INSERT INTO @testRight (ID, SomeOtherValue) VALUES (3, 'Z')

SELECT l.*
FROM 
    @testLeft l
     LEFT JOIN 
    @testRight r ON 
        l.ID = r.ID
WHERE r.ID IS NULL 
2
AHiggins

Cette page donne une ventilation correcte des différents types de jointures, ainsi que des visualisations de diagrammes venn pour vous aider à bien visualiser la différence entre les jointures.

Comme les commentaires l'indiquent, il s'agit d'une requête assez élémentaire. Vous devriez donc essayer de comprendre les différences entre les jointures et leur signification réelle.

Découvrez http://blog.codinghorror.com/a-visual-explanation-of-sql-joins/

Vous recherchez une requête telle que:

DECLARE @table1 TABLE (test int)
DECLARE @table2 TABLE (test int)

INSERT INTO @table1
(
    test
)
SELECT 1
UNION ALL SELECT 2

INSERT INTO @table2
(
    test
)
SELECT 1
UNION ALL SELECT 3

-- Here's the important part
SELECT  a.*
FROM    @table1 a
LEFT    join @table2 b on a.test = b.test -- this will return all rows from a
WHERE   b.test IS null -- this then excludes that which exist in both a and b

-- Returned results:

2
1
Kritner

sélectionnez * dans la table de gauche sans champ clé (sélectionnez le champ clé dans la table de droite)

0
George Let

Ceci est un exemple de travail dans la vie réelle, on m'a demandé de fournir une liste d'utilisateurs qui ont acheté de notre site au cours des 6 derniers mois mais pas au cours des 3 derniers mois.

Pour moi, la façon la plus compréhensible à laquelle je puisse penser est la suivante:

--Users that bought from us 6 months ago and between 3 months ago.
DECLARE @6To3MonthsUsers table (UserID int,OrderDate datetime)
INSERT @6To3MonthsUsers
    select u.ID,opd.OrderDate
        from OrdersPaid opd
        inner join Orders o
        on opd.OrderID = o.ID
        inner join Users u
        on o.BuyerID = u.ID
        where 1=1 
        and opd.OrderDate BETWEEN DATEADD(m,-6,GETDATE()) and DATEADD(m,-3,GETDATE())

--Users that bought from us in the last 3 months
DECLARE @Last3MonthsUsers table (UserID int,OrderDate datetime)
INSERT @Last3MonthsUsers
    select u.ID,opd.OrderDate
        from OrdersPaid opd
        inner join Orders o
        on opd.OrderID = o.ID
        inner join Users u
        on o.BuyerID = u.ID
        where 1=1 
        and opd.OrderDate BETWEEN DATEADD(m,-3,GETDATE()) and GETDATE()

Maintenant, avec ces 2 tables dans mes mains, je n'ai besoin que de récupérer les utilisateurs de la table @ 6To3MonthsUsers qui ne figurent pas dans @ Last3MonthsUsers table.

Il y a 2 façons simples d'y parvenir:

  1. Utiliser la jointure gauche:

    select distinct a.UserID
    from @6To3MonthsUsers a
    left join @Last3MonthsUsers b
    on a.UserID = b.UserID
    where b.UserID is null
    
  2. Pas dedans:

    select distinct a.UserID
    from @6To3MonthsUsers a
    where a.UserID not in (select b.UserID from @Last3MonthsUsers b)
    

Les deux méthodes me permettent d'obtenir le même résultat, personnellement, je préfère la deuxième méthode, car elle est plus lisible.

0
Offir Pe'er