web-dev-qa-db-fra.com

Pourquoi les jointures à plusieurs tables produisent-elles des lignes en double?

Disons que j'ai trois tables A, B et C. Chacune a deux colonnes: une clé primaire et une autre donnée. Ils ont chacun le même nombre de lignes. Si je JOIN A et B sur la clé primaire, je devrais me retrouver avec le même nombre de lignes que dans l'une d'elles (par opposition à A.rows * B.rows).

Maintenant, si je JOINA JOIN B avec C, pourquoi me retrouve-t-il avec des lignes en double? J'ai rencontré ce problème à plusieurs reprises et je ne le comprends pas. Il semble que cela devrait produire le même résultat que JOINing A et B puisqu'il contient le même nombre de lignes mais que des doublons sont générés.

Les requêtes qui produisent de tels résultats sont au format

SELECT *
FROM M
    INNER JOIN S
        on M.mIndex = S.mIndex
    INNER JOIN D
        ON M.platformId LIKE '%' + D.version + '%'
    INNER JOIN H
        ON D.Name = H.Name
        AND D.revision = H.revision

Voici les schémas pour les tables. H contient est un tableau historique contenant tout ce qui a jamais été en D. Il y a beaucoup de lignes M pour chaque D et un S pour chaque M.

Tableau m

    [mIndex] [int] NOT NULL PRIMARY KEY,
    [platformId] [nvarchar](256) NULL,
    [ip] [nvarchar](64) NULL,
    [complete] [bit] NOT NULL,
    [date] [datetime] NOT NULL,
    [DeployId] [int] NOT NULL PRIMARY KEY REFERENCES D.DeployId,
    [source] [nvarchar](64) NOT NULL PRIMARY KEY

Les tables

[order] [int] NOT NULL PRIMARY KEY,
[name] [nvarchar](64) NOT NULL,
[parameters] [nvarchar](256) NOT NULL,
[Finished] [bit] NOT NULL,
[mIndex] [int] NOT NULL PRIMARY KEY,
[mDeployId] [int] NOT NULL PRIMARY KEY,
[Date] [datetime] NULL,
[status] [nvarchar](10) NULL,
[output] [nvarchar](max) NULL,
[config] [nvarchar](64) NOT NULL PRIMARY KEY

Tableau d

[Id] [int] IDENTITY(1,1) NOT NULL PRIMARY KEY,
[branch] [nvarchar](64) NOT NULL,
[revision] [int] NOT NULL,
[version] [nvarchar](64) NOT NULL,
[path] [nvarchar](256) NOT NULL

Tableau h

[IdDeploy] [int] IDENTITY(1,1) NOT NULL,
[name] [nvarchar](64) NOT NULL,
[version] [nvarchar](64) NOT NULL,
[path] [nvarchar](max) NOT NULL,
[StartDate] [datetime] NOT NULL,
[EndDate] [datetime] NULL,
[Revision] [nvarchar](64) NULL,

Je n'ai pas posté les tables et interrogé initialement parce que je suis plus intéressé à comprendre ce problème par moi-même et à l'éviter à l'avenir.

24
sirdank

Si l’une des tables M, S, D ou H a plus d’une ligne pour un Id donné (si seulement la colonne Id n’est pas la clé primaire), la requête aboutirait à des lignes "en double". Si vous avez plus d'une ligne pour un Id dans une table, les autres colonnes, qui identifieraient de manière unique une ligne, doivent également être incluses dans la ou les conditions JOIN.

Références :

Question connexe sur le forum MSDN

19
Joseph B

Lorsque vous avez des tables associées, vous avez souvent des relations un à plusieurs ou plusieurs à plusieurs. Ainsi, lorsque vous rejoignez TableB, chaque enregistrement de TableA contient plusieurs enregistrements dans TableB. Ceci est normal et attendu.

Parfois, vous n'avez besoin que de certaines colonnes et celles-ci sont identiques pour tous les enregistrements. Vous devez alors créer une sorte de groupe par ou distinct pour supprimer les doublons. Regardons un exemple:

TableA
Id Field1
1  test
2  another test

TableB
ID Field2 field3
1  Test1  something
1  test1  More something
2  Test2  Anything

Donc, lorsque vous les rejoignez et sélectionnez tous les fichiers que vous obtenez:

select * 
from tableA a 
join tableb b on a.id = b.id

a.Id a.Field1        b.id   b.field2  b.field3
1    test            1      Test1     something
1    test            1      Test1     More something
2    another test 2  2      Test2     Anything

Ce ne sont pas des doublons car les valeurs de Field3 sont différentes même s'il existe des valeurs répétées dans les champs précédents. Désormais, lorsque vous ne sélectionnez que certaines colonnes, le même nombre d'enregistrements sont joints mais, comme les colonnes contenant les différentes informations ne sont pas affichées, elles ressemblent à des doublons.

select a.Id, a.Field1,  b.field2
from tableA a 
join tableb b on a.id = b.id

a.Id a.Field1       b.field2  
1    test           Test1     
1    test           Test1 
2    another test   Test2

Cela semble être des doublons, mais ce n'est pas à cause des enregistrements multiples dans TableB.

Vous corrigez normalement cela en utilisant des agrégats et un groupe par, en utilisant distinct ou en filtrant dans la clause where pour supprimer les doublons. Votre solution dépend de la nature exacte de votre règle métier, de la conception de votre base de données et du type de données qu’elle contient.

26
HLGEM

Cela peut sembler une réponse "DUH" très basique, mais assurez-vous que la colonne que vous utilisez pour la recherche dans le fichier de fusion est en réalité pleine de valeurs uniques!

J'ai remarqué plus tôt dans la journée que PowerQuery ne vous lança pas d'erreur (comme dans PowerPivot) et vous autoriserait à exécuter une fusion plusieurs-plusieurs. Cela entraînera la production de plusieurs lignes pour chaque enregistrement correspondant à une valeur non unique.

1
Jonathan Josh

Ok dans cet exemple, vous obtenez des doublons parce que vous joignez D et S à M. Je suppose que vous devriez joindre D.id à S.id comme ci-dessous:

SELECT *
FROM M
INNER JOIN S
    on M.Id = S.Id
INNER JOIN D
    ON S.Id = D.Id
INNER JOIN H
    ON D.Id = H.Id
0
CathalMF