SQL kartesisches beitreten Problem
-
22-07-2019 - |
Frage
Ich habe drei Tabellen
- A: A.pID Primärschlüssel, A.Name nvarchar (250)
- B: B.pID Primärschlüssel, B.Name nvarchar (250)
- C: C.pID Primärschlüssel, C.Name nvarchar (250)
Es ist ein m zu n Beziehung zwischen A und B (Tabelle lA_B
mit Primärschlüssel lA_B.pID
und .pInstanceA
Fremdschlüssel für Tabelle A und .pInstanceB
Fremdschlüssel für Tabelle B)
Es ist ein m zu n Beziehung zwischen A und C (table lA_C
mit Primärschlüssel lA_C.pID
und .pInstanceA
Fremdschlüssel für Tabelle A und .pInstanceB
Fremdschlüssel für Tabelle C)
- A1 ist im Zusammenhang mit B1, B2 und C1
- A2 ist in Verbindung mit B3 und C2, C3
- A3 ist in Verbindung mit B4
- A4 ist in Verbindung mit C4
- A5 hat keine Beziehung
Hier ist meine 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)
Diese Abfrage:
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)
Rückkehr
A1 B1 C1 A1 B2 C1 A2 B3 C2 A2 B3 C3 A3 B4 NULL A4 NULL C4 A5 NULL NULL
Und nun die Frage :-) wie die Abfrage
erhaltenA1 B1 NULL A1 B2 NULL A1 NULL C1 A2 B3 NULL A2 NULL C2 A2 NULL C3 A3 B4 NULL A4 NULL C4 A5 NULL NULL
Das Problem ist, dass, wenn ich die beiden machen verbinden mit B und C das Ergebnis alle Kombinationen von B C. hat Wie kann ich diese beseitigen?
Lösung
Das könnte Sie der Lage sein, das zu tun mit einer 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)
Der erste Teil wählt alle Kombinationen von A und B, den zweiten Teil aller Kombinationen von A und C liegt.
Wenn Sie möchten, um herauszufiltern Zeilen wie (A4, NULL, NULL), weil es bereits eine Reihe (A4, NULL, C4), versuchen Sie diese Abfrage:
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
auf B die Verbindung, das sagt Zeilen umfasst, die eine Übereinstimmung in B haben, oder für die es keine Übereinstimmung in C. Der Join auf C enthält nur die Zeilen, die Übereinstimmung in C. Zeilen, die nicht übereinstimmen würden entweder erhalten von der Join auf B enthalten.
Beachten Sie, dass UNION doppelte Zeilen herausfiltert, wie DISTINCT. Um jede Zeile gehören, können Sie UNION ALL verwenden.
Andere Tipps
Ich denke, das tut es:
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