2009-05-08 10 views
1

J'ai trois tablescartésienne SQL rejoindre problème

  • A: clé primaire A.pID, A.Name nvarchar (250)
  • B: B.pID clé primaire, B.Name nvarchar (250)
  • C: C.pID clé primaire, C.Name nvarchar (250)

Il y a h à n relation entre A et B (tableau lA_B avec clé primaire clé étrangère lA_B.pID et .pInstanceA au tableau A et .pInstanceB Clé étrangère au tableau B)

Il y a h à n relation entre A et C (table lA_C avec clé primaire clé étrangère lA_C.pID et .pInstanceA au tableau A et .pInstanceB Clé étrangère au tableau C)

  • A1 est en relation avec B1, B2 et C1
  • A2 est en relation avec B3 et C2, C3
  • A3 est en relation avec B4
  • A4 est en relation avec C4
  • A5 n'a aucune relation

Voici mon SQL:

CREATE TABLE [dbo].[A]([pID] [bigint] NOT NULL, [Name] [nvarchar](250) NULL) 
CREATE TABLE [dbo].[B]([pID] [bigint] NOT NULL, [Name] [nvarchar](250) NULL) 
CREATE TABLE [dbo].[C]([pID] [bigint] NOT NULL, [Name] [nvarchar](250) NULL) 
CREATE TABLE [dbo].[lA_B]([pID] [bigint] NOT NULL, [pInstanceA] [bigint] NULL, [pInstanceB] [bigint] NULL) 
CREATE TABLE [dbo].[lA_C]([pID] [bigint] NOT NULL, [pInstanceA] [bigint] NULL, [pInstanceB] [bigint] NULL) 

INSERT INTO [dbo].[A] ([pID] ,[Name]) VALUES (1,'A1') 
INSERT INTO [dbo].[A] ([pID] ,[Name]) VALUES (2,'A2') 
INSERT INTO [dbo].[A] ([pID] ,[Name]) VALUES (3,'A3') 
INSERT INTO [dbo].[A] ([pID] ,[Name]) VALUES (4,'A4') 
INSERT INTO [dbo].[A] ([pID] ,[Name]) VALUES (5,'A5') 

INSERT INTO [dbo].[B] ([pID] ,[Name]) VALUES (1,'B1') 
INSERT INTO [dbo].[B] ([pID] ,[Name]) VALUES (2,'B2') 
INSERT INTO [dbo].[B] ([pID] ,[Name]) VALUES (3,'B3') 
INSERT INTO [dbo].[B] ([pID] ,[Name]) VALUES (4,'B4') 

INSERT INTO [dbo].[C] ([pID] ,[Name]) VALUES (1,'C1') 
INSERT INTO [dbo].[C] ([pID] ,[Name]) VALUES (2,'C2') 
INSERT INTO [dbo].[C] ([pID] ,[Name]) VALUES (3,'C3') 
INSERT INTO [dbo].[C] ([pID] ,[Name]) VALUES (4,'C4') 

INSERT INTO [dbo].[lA_B] ([pID],[pInstanceA],[pInstanceB]) VALUES (1,1,1) 
INSERT INTO [dbo].[lA_B] ([pID],[pInstanceA],[pInstanceB]) VALUES (2,1,2) 
INSERT INTO [dbo].[lA_B] ([pID],[pInstanceA],[pInstanceB]) VALUES (3,2,3) 
INSERT INTO [dbo].[lA_B] ([pID],[pInstanceA],[pInstanceB]) VALUES (4,3,4) 

INSERT INTO [dbo].[lA_C] ([pID],[pInstanceA],[pInstanceB]) VALUES (1,1,1) 
INSERT INTO [dbo].[lA_C] ([pID],[pInstanceA],[pInstanceB]) VALUES (2,2,2) 
INSERT INTO [dbo].[lA_C] ([pID],[pInstanceA],[pInstanceB]) VALUES (3,2,3) 
INSERT INTO [dbo].[lA_C] ([pID],[pInstanceA],[pInstanceB]) VALUES (4,4,4) 

cette requête:

SELECT 
    A.Name AS A, 
    B.Name AS B, 
    C.Name AS C 
FROM 
    A 
    left JOIN lA_B ON (A.pID = lA_B.pInstanceA) 
    left JOIN B  ON (B.pID = lA_B.pInstanceB) 
    left JOIN lA_C ON (A.pID = lA_C.pInstanceA) 
    left JOIN C  ON (C.pID = lA_C.pInstanceB) 

retours

 
A1  B1  C1 
A1  B2  C1 
A2  B3  C2 
A2  B3  C3 
A3  B4  NULL 
A4  NULL C4 
A5  NULL NULL 

Et maintenant la question :-) comment interroger pour recevoirLe problème est que lorsque je fais la jointure à la fois avec B et avec C le résultat a toutes les combinaisons de B C. Comment puis-je l'éliminer?

+0

Les instructions CREATE TABLE semblent être écourtée, pourriez-vous modifier le message et les inclure en entier? – Andomar

Répondre

4

Vous pourriez être en mesure de le faire avec un UNION:

SELECT A.Name AS A, B.Name AS B, NULL AS C 
FROM A 
left JOIN lA_B ON (A.pID=lA_B.pInstanceA) 
left JOIN B ON (lA_B.pInstanceB=B.pID) 
UNION 
SELECT A.Name AS A, NULL AS B, C.Name AS C 
FROM A 
left JOIN lA_C ON (A.pID=lA_C.pInstanceA) 
left JOIN C ON (lA_C.pInstanceB=C.pID) 

La première partie sélectionne toutes les combinaisons de A et B, la deuxième partie de toutes les combinaisons de A et C.

Si vous souhaitez pour filtrer les lignes comme (A4, NULL, NULL) car il y a déjà une rangée (A4, NULL, C4), essayez cette requête:

SELECT A.Name AS A, B.Name AS B, NULL AS C 
FROM A 
LEFT JOIN lA_B ON (A.pID=lA_B.pInstanceA) 
LEFT JOIN B ON (lA_B.pInstanceB=B.pID) 
WHERE b.name is not null 
    or not exists(select * from lA_C where A.pID=lA_C.pInstanceA) 
UNION 
SELECT A.Name AS A, NULL AS B, C.Name AS C 
FROM A 
LEFT JOIN lA_C ON (A.pID=lA_C.pInstanceA) 
LEFT JOIN C ON (lA_C.pInstanceB=C.pID) 
WHERE c.name is not null 
ORDER BY A,B,C 

pour le rejoindre sur B, ce dit inclure les lignes qui ont un match en B, ou pour lequel La jointure sur C n'inclut que les lignes qui correspondent à C. Les lignes qui ne correspondent pas seront incluses à partir de la jointure sur B.

Notez que UNION filtre les lignes en double, comme DISTINCT. Pour inclure chaque ligne, vous pouvez utiliser UNION ALL.

+0

A1 \t NULL \t NULL A1 \t B1 \t NULL A1 \t B2 \t NULL A2 \t NULL \t NULL A2 \t B3 \t NULL A3 \t NULL \t NULL A3 \t B4 \t NULL A4 \t NULL \t NULL A5 \t NULL NULL \t est pas tout à fait ok .... Je ne pas besoin de ces lignes A1 \t NULL NULL \t A2 \t NULL NULL \t A3 \t NULL NULL \t – bogdanbrudiu

+0

@Andomar - Il semble que vous avez déjà édité votre réponse pour refléter le commentaire de @ bogdanbrudiu? Il serait utile de noter cela dans le texte de la réponse. – ahains

+0

@hainstech: modification de la réponse après la publication de la définition de table complète, mais avant que j'aie vu le commentaire. Le montage est à peu près la même chose. – Andomar

0

Je pense que cela le fait:

select a, 
     case when b='zzz' then null else b end as b, 
     case when c='zzz' then null else c end as c 
from (SELECT A.Name AS A 
      ,b.Name as b 
      ,'zzz' as c 
     FROM A  
     JOIN lA_B ON (A.pID = lA_B.pInstanceA) 
     JOIN B  ON (B.pID = lA_B.pInstanceB) 
     union 
     select a.Name 
      ,'zzz' 
      ,c.NAme 
     from A 
     left JOIN lA_C ON (A.pID = lA_C.pInstanceA) 
     left JOIN C  ON (C.pID = lA_C.pInstanceB)) as a 
+0

Que se passerait-il si 'zzz' était un nom réel? – Andomar

+0

Eh bien, vous vivez est un endroit assez étrange, ou vous ne validez pas l'entrée dans la colonne Nom. Dans ce cas, vous êtes seul! – StewNoble