2016-08-12 1 views
4

Ich versuche wahrscheinlich, JOINs für Zwecke zu verwenden, die sie hier nicht beabsichtigten.Gibt es eine Möglichkeit, dass diese Abfrage mit JOINs funktioniert oder muss ich eine UNION verwenden?

Hier ist meine (vereinfacht) Tabellenstruktur:

Tabelle A

  • ID
  • Tabelle C ID
  • IsStatic (Bit)

Tabelle B

  • ID
  • Tabelle A-ID (nullable)
  • Tabelle C ID

Tabelle C

  • ID

Mein Ziel ist es verbunden alle Tabelle B Zeilen zu erhalten Tabelle A Zeilen, in denen die Tabelle A ID-Spalte von Tabelle B einen Wert hat und dem ID-Spaltenwert von Tabelle A entspricht.

Ich brauche auch alle Tabelle B Zeilen, wo Tabelle B's Tabelle A ID Spalte keinen Wert hat.

Ich brauche auch alle Tabelle A Zeilen mit keine verbunde Tabelle B Zeilen und Tabelle Isstatic Spalte ist wahr.

Tabelle C muss auch mit Tabelle A oder Tabelle B verknüpft sein. Wenn Tabelle B keinen Wert für TableAID aufweist, sollte der Wert für TableCID dem ID-Wert von TableC entsprechen. Andernfalls sollte TableAs TableCID dem ID-Wert von TableC entsprechen.

Hier einige SQL einige TABLE-Variablen zu erstellen und mit Beispieldaten füllen:

DECLARE @TableA TABLE (TableAID int, TableCID int, IsStatic bit) 
DECLARE @TableB TABLE (TableBID int, TableAID int, TableCID int) 
DECLARE @TableC TABLE (TableCID int) 

INSERT INTO @TableC (TableCID) VALUES (1) 
INSERT INTO @TableC (TableCID) VALUES (2) 

INSERT INTO @TableA (TableAID, TableCID, IsStatic) VALUES (1, 1, 0) 
INSERT INTO @TableA (TableAID, TableCID, IsStatic) VALUES (2, 2, 1) 
INSERT INTO @TableA (TableAID, TableCID, IsStatic) VALUES (3, 2, 1) 
INSERT INTO @TableA (TableAID, TableCID, IsStatic) VALUES (4, 2, 0) 

INSERT INTO @TableB (TableBID, TableAID, TableCID) VALUES (1, NULL, 1) 
INSERT INTO @TableB (TableBID, TableAID, TableCID) VALUES (2, 1, 1) 
INSERT INTO @TableB (TableBID, TableAID, TableCID) VALUES (3, 2, 2) 

Hier ist meine (vereinfacht) Abfrage, die nicht ganz funktioniert hat:

SELECT 
    a.TableAID, 
    b.TableBID 
FROM @TableC c 
LEFT OUTER JOIN @TableB b ON 
    (b.TableAID IS NOT NULL OR (b.TableAID IS NULL AND b.TableCID = c.TableCID)) 
LEFT OUTER JOIN @TableA a ON 
    a.TableCID = c.TableCID 
    AND ((a.IsStatic = 1 AND b.TableBID IS NULL) 
     OR (b.TableBID IS NOT NULL AND b.TableAID = a.TableAID)) 

Das Ergebnis dieser Abfrage das Sampel Daten ist:

TableAID TableBID 
----------------- 
NULL  1 
1  2 
NULL  3  (not required) 
NULL  2  (not required) 
2  3 

das erforderliche Ergebnis ist:

TableAID TableBID 
----------------- 
NULL  1 
3  NULL  (missing) 
2  3 
1  2 

Problem mit dieser Abfrage ist, dass wenn TableB.TableAID keinen Wert hat dann die Tabelle A Zeilen, in denen TableA.IsStatic ohne passende TableB Reihen wahr sind nie enthalten. Außerdem sind einige TableB-Zeilen enthalten, die nicht enthalten sein sollten.

Der einzige andere Weg, den ich sehen kann, ist mit einer union mit einer not exists, aber ich hatte gehofft, dies auf eine effizientere Weise zu tun.

Aktualisierung: Das Hinzufügen einer WHERE-Klausel entfernt die Zeilen "not required", lässt aber die fehlende Zeile immer noch aus.

WHERE (b.TableBID IS NULL OR b.TableAID IS NULL OR b.TableAID = a.TableAID) 

Das Ergebnis der gleichen Abfrage mit der where-Klausel ist:

TableAID TableBID 
----------------- 
NULL  1 
1  2 
2  3 
+0

In Ihrem Joins versuchen Sie dies stattdessen. JOIN-Tabelle ON ISNULL (table.column, '') = ISNULL (otherTable.column, ''). Vergib mir meine Formatierung. Ich bin auf meinem Handy. – scsimon

+0

Joins dienen zum Kombinieren von Spalten in einer einzelnen Zeile. Sie versuchen, Zeilen zu einer einzigen Ergebnismenge zusammenzufassen. Dafür sind Gewerkschaften da. Ihre Abfrage wird einfacher zu verwalten und zu verstehen sein, wenn Sie nur eine Union verwenden. Gibt es einen Grund, warum du es vermeiden willst? –

+1

@MikeD. - Angst vor Engagement! (Witze ... Union, verstehst du?) Im Ernst, ich dachte, ich müsste ein ineffizientes "nicht vorhanden" in der Abfrage haben, die ich vermeiden wollte. Aber Antons Antwort vermeidet das und ich sehe nur, ob das für mich funktioniert. – johna

Antwort

2

Was für ein Geist Twister. Ich denke, das ist eine andere Art, es auszudrücken. Sie werden sehen, wenn die Leistung gut ist oder nicht:

select a.TableAID, b.TableBID 
    from (select a.* 
      from @TableA a 
      join @TableC c 
      on c.TableCID = a.TableCID) a 
    full outer join (select b.* 
        from @TableB b 
        join @TableC c 
         on c.TableCID = b.TableCID) b 
    on b.TableAID = a.TableAID 
where b.TableBID is not null or a.IsStatic = 1 

Ich sollte auch erwähnen, dass es sicher schwer zu wissen, ist, wenn die obige Abfrage Ihre Anforderungen mit Hilfe der Beispieldaten wirklich respektiert Sie zur Verfügung gestellt. Zur Veranschaulichung, wenn ich diese vereinfachte Abfrage unter dem einfach die Tabelle @TableC ignoriert, bekomme ich immer noch die richtigen Ergebnisse mit Beispieldaten:

select a.TableAID, b.TableBID 
    from @TableA a 
    full outer join @TableB b 
    on b.TableAID = a.TableAID 
where b.TableBID is not null or a.IsStatic = 1 

EDIT: Lustige Diskussion in den Kommentaren über die Auslegung des OP‘ Anforderungen ... Aber wenn ich Antons Punkt ansprechen musste:

select a.TableAID, b.TableBID 
    from (select a.*, 
       case when c.TableCID is not null then 1 end as has_c 
      from @TableA a 
      left join @TableC c 
      on c.TableCID = a.TableCID) a 
    full outer join (select b.*, 
          case when c.TableCID is not null then 1 end as has_c 
        from @TableB b 
        left join @TableC c 
         on c.TableCID = b.TableCID) b 
    on b.TableAID = a.TableAID 
where (b.TableBID is not null or a.IsStatic = 1) 
    and (a.has_c = 1 or b.has_c = 1) 
+0

Es scheint, dass dieses Skript falsch ist, wenn wir die Beispieldaten ändern. Versuchen Sie, INSERTs für TableB VALUES (2, 1, 1) durch VALUES (2, 1, 3) zu ersetzen – Anton

+0

Sie vermissen es, anzuzeigen (1, 2) – Anton

+0

@Anton, (2, 1, 3) ist nicht gültig wie Tabelle3 habe keinen Beispielzeilen-ID-Wert von 3. (1, 2) wird für mich angezeigt. – johna

4
select b.TableAID, b.TableBID 
from @TableB b 
    left join @TableA a on a.TableAID = b.TableAID 
    inner join @TableC c on c.TableCID = case when a.TableAID IS NULL then b.TableCID else a.TableCID end 

union all 

select a.TableAID, NULL 
from @TableA a 
    inner join @TableC c on c.TableCID = a.TableCID 
    left join @TableB b on b.TableAID = a.TableAID 
where b.TableAID is NULL 
    and a.IsStatic = 1 
+0

Diese Antwort funktioniert wirklich gut. Allerdings akzeptierte ich @stans Antwort, da der Ausführungsplan und die Geschwindigkeit besser waren (mehr aufgrund der realen Datenstruktur und Indexierung). Vielen Dank für die Antwort und ich kann bestätigen, dass es perfekt mit der realen Struktur und den Daten funktionierte. – johna

Verwandte Themen