2012-04-02 8 views
0

Tabelle B enthält geplante Werte. Tabelle M enthält tatsächliche Werte. Ich muss alle Zeilen in Tabelle B finden, in denen entweder keine tatsächlichen Werte (z. B. verbunden) Zeile in Tabelle M sind, oder wo verbundene Zeilen unterschiedliche Gesamt-Istwert-Zeilen haben. Ich versuche eine Kombination aus einem äußeren Join und der Summe ... Gruppe um dies zu erreichen, aber es funktioniert nicht, weil die 'Waisen' in Tabelle B nicht zurückgegeben werden.SQL Server mit linkem Join/mit Summe/Gruppe von

Meine Frage ist: -

SELECT B.Id, B.Date, b.Ref,SUM(M.Actual_Volume), SUM(B.Planned_Volume), 
SUM(M.Actual_Value),SUM(B.Planned_Value) 
FROM 
TableB B 
left JOIN TableM M on M.Id = B.Id 
inner JOIN TableX on TableX.FieldX = B.FieldX 
WHERE TableX.FieldY = (SELECT T.FieldY from TableX T where T.FieldX = 408344) 
AND TableX.FieldZ = (SELECT T1.FieldZ from TableX T1 where T1.FieldX = 408344) 
group by B.Id, B.Date, B.Ref 
having SUM(M.Actual_Volume) <> SUM(B.Planned_Volume) 
OR SUM(M.Actual_Value) <> SUM(B.Planned_Value) 
order by b.Id 

Wenn ich = statt <> die Wirklichkeiten zu vergleichen und ich geplant Reihen erhalten, die beitreten, aber ich brauche die Zeilen, in denen die Wirklichkeiten nicht gleich tun die geplante oder wo es eine geplante aber keine tatsächliche gibt.

Danke!

Table B 
Id planned_vol planned val 
19 2   350 
28 1   100 
53 3   650 
61 1   50 

Table M 
M.Id B.Id actual_vol actual_val 
58 19 2   350 
65 28 1   100 
66 53 1   150 

die Abfrage sollte also zurückkehren,

B.Id 
53 (because planned_vol <> actual_vol and planned_val <> actual_val) 
61 (because B.Id 61 is not in table M) 

hth!

+3

Können Sie einige Beispieldaten für die Zeilen zeigen Sie, dass Sie (aus beiden Gründen) und mindestens eine Zeile zurückgegeben werden sollen, die Sie nicht tun will zurückgegeben werden. –

+0

Quick-Fix wäre hinzuzufügen 'SUM (M.Actual_Volume) ist Null oder SUM (M.Actual_Value) ist null' zu haben, aber ich denke, dass Sie versuchen, beide Seiten der n: m Beziehung zu summieren. Dies wird mit der Datenduplikation enden. Könnten Sie mehr Informationen über Ihr Schema und Ihre Beziehung zwischen M und B veröffentlichen? –

+0

Ja, tableB zu TableM ist m: m, weil die definierende Tabelle TableX ist – epx

Antwort

1

Dies ist nicht getestet, aber ich denke, Sie müssen die Anforderungen in die linken äußeren Join Anforderungen verschieben. Die Verwendung von CTEs (d. H. Sie müssen SQL Server 2005 oder höher verwenden, damit dies funktioniert) ist eine Möglichkeit, dies zu tun.

Ihre having-Klausel zwingt SQL Server, den B-M-Join als inneren Join zu behandeln. Es kann einen alternativen Ansatz geben, der keine CTEs verwendet, die an allen richtigen Stellen nach NULLs suchen. Aber ich bevorzuge den "Teile-und-herrsche" Ansatz.

WITH 
[BAlt] AS 
(
    SELECT 
     [B].[Id], 
     [B].[Date], 
     [B].[Ref], 
     SUM([B].[Planned_Volume]) AS [Planned_Volume], 
     SUM([B].[Planned_Value]) AS [Planned_Value], 
    FROM [TableB] AS [B] 
     INNER JOIN [TableX] AS [X1] ON [X1].[FieldX] = [B].[FieldX] 
      AND [X1].[FieldY] = 
      (
       SELECT 
        [X2].[FieldY] 
       FROM [TableX] AS [X2] 
       WHERE [X2].[FieldX] = 408344 
      ) 
      AND [X1].[FieldZ] = 
      (
       SELECT 
        [X3].[FieldZ] 
       FROM [TableX] AS [X2] 
       WHERE [X3].[FieldX] = 408344 
      ) 
    GROUP BY 
     [B].[Id], 
     [B].[Date], 
     [B].[Ref] 
), 
[MAlt] AS 
(
    SELECT 
     [M].[Id], 
     SUM([M].[Actual_Volume]) AS [Actual_Volume], 
     SUM([M].[Actual_Value]) AS [Actual_Value] 
    FROM [M] 
    GROUP BY 
     [M].[Id] 
) 
SELECT 
    [BAlt].[Id], 
    [BAlt].[Date], 
    [BAlt].[Ref], 
    [BAlt].[Planned_Volume], 
    [BAlt].[Planned_Value], 
    [MAlt].[Actual_Volume], 
    [MAlt].[Actual_Value] 
FROM [BAlt] 
    LEFT OUTER JOIN [MAlt] ON [MAlt].[Id] = [BAlt].[Id] 
     AND 
     (
      [MAlt].[Actual_Volume] <> [BAlt].[Planned_Volume] 
       OR [MAlt].[Actual_Value] <> [BAlt].[Planned_Value] 
     ) 
ORDER BY 
    [BAlt].[Id] 
+0

Ich benutze SQL Server 2005 9.00.1399.06, so werde ich dies geben – epx

+0

Daniel, auf diese Weise versuchen, die richtigen Sätze AS SELECT Klauseln ausgewählt werden, aber aus irgendeinem Grund die endgültige SELECT nicht korrekt beitreten und NULL zurückgibt für die Felder Actual_Volume und Actual_Value. Irgendwelche Gedanken zur Reparatur? – epx

+0

@epx 'Actual_Volume' und' Actual_Value' sind in den Fällen null, in denen eine ID in 'B' existiert, aber nicht in' M'. Wenn Sie einen Standardwert wünschen, z.B. Null, benutze 'ISNULL ([MAlt]. [Actual_Volume], 0)' und äquivalent zu 'Actual_Value' in der final select-Klausel. –

0

Ich habe kein Problem sehen wirklich:

create table b 
    ( B_id int 
     ,PlannedVolume int 
     ,PlannedValue int 
    ) 

    create table M 
    ( M_id int 
     ,B_id int 
     ,ActualVolume int 
     ,ActualValue int 
    ) 

    insert b (b_id, PlannedVolume, PlannedValue) 
    values (19, 2, 350), 
     (28, 1, 100), 
     (53, 3, 650), 
     (61, 1, 50) 

    insert m (m_id, b_id, ActualVolume, ActualValue) 
    values (58, 19, 2, 350), 
     (65, 28, 1, 100), 
     (66, 53, 1, 150), 
     (67, 53, 1, 100) 

    select b.b_id 
    from b 
    left join 
    ( select b_id 
      ,sum(ActualVolume) as ActualVolume 
      ,sum(ActualValue) as ActualValue 
     from m 
     group by b_id 
    ) m  
    on m.b_id = b.b_id 
    where 
    m.b_id is null 
    or 
    (m.ActualValue <> b.PlannedValue and m.ActualVolume <> b.PlannedVolume) 
+0

das Problem ist, es ist nicht 1: 1 zwischen b und m, also in m könnte man auch die Reihe 67,53,1,100 haben. So, jetzt für b_id 53 haben wir jetzt ein hervorragendes planed_volume von 1 und einen hervorragenden planed_value von 400, weshalb ich GROUP BY ... HAVING SUM versucht habe, aber es ist noch nicht da :-( – epx

+0

I aktualisierter Kommentar. Take ein Blick. – zejafo