2012-06-22 17 views
7

OK - Ho guardato e cercato e ho trovato molti esempi, ma niente soddisfaceva il mio bisogno. Forse ho usato le parole sbagliate per cercare, ma potrei usare il tuo aiuto. Fornirò il maggior numero di dettagli possibile.Come rimuovere le righe duplicate dall'istruzione unione

Ho bisogno di produrre un report che unisca campi da due tabelle, o meglio una vista e una tabella, in una tabella per un report. Ecco la dichiarazione che sto usando:

SELECT A.ConfInt, A.Conference, 
     NULL as Ordered, 
     NULL as Approved, 
     NULL as PickedUp, 
     SUM(dbo.Case_Visit_Payments.Qty) AS Qty 
FROM   dbo.Conferences as A INNER JOIN 
         dbo.Case_Table ON A.ConfInt = dbo.Case_Table.Conference_ID INNER JOIN 
         dbo.Case_Visit_Payments ON dbo.Case_Table.Case_ID = dbo.Case_Visit_Payments.Case_ID 
WHERE  (dbo.Case_Visit_Payments.Item_ID = 15 AND A.ProjectCool = 1) 
GROUP BY A.Conference, A.ConfInt 
UNION 
SELECT B.ConfInt, 
     B.Conference, 
     SUM(dbo.Cool_Fan_Order.NumberOfFansRequested) AS Ordered, 
     SUM(dbo.Cool_Fan_Order.Qty_Fans_Approved) AS Approved, 
     SUM(dbo.Cool_Fan_Order.Qty_Fans_PickedUp) AS PickedUp, 
     NULL AS Qty 
FROM   dbo.Conferences as B LEFT OUTER JOIN 
         dbo.Cool_Fan_Order ON B.ConfInt = dbo.Cool_Fan_Order.Conference_ID 
where B.ProjectCool = 1 
GROUP BY B.Conference, B.ConfInt 

Ed ecco i risultati:

4 Our Lady  NULL NULL NULL 11 
4 Our Lady  40  40  40  NULL 
7 Holy Rosary  20  20  20  NULL 
11 Little Flower NULL NULL NULL 21 
11 Little Flower 5  5  20  NULL 
19 Perpetual Help NULL NULL NULL 2 
19 Perpetual Help 20  20  20  NULL 

Quello che vorrei fortemente preferisco è quello di non avere le righe duplicazione, come ad esempio:

4 Our Lady  40  40  40  11 
7 Holy Rosary  20  20  20  NULL 
11 Little Flower 5  5  20  21 
19 Perpetual Help 20  20  20  2 

Spero che questa domanda sia stata abbastanza chiara. Ogni suggerimento sarà molto apprezzato. E segnalo come risposta. :)

Gregory

risposta

5

la risposta rapida è quello di avvolgere la query all'interno di un altro,

SELECT ConfInt 
    , Conference 
    , SUM(Ordered) AS Ordered 
    , SUM(Approved) As Approved 
    , SUM(PickedUp) AS PickedUp 
    , SUM(Qty) AS Qty 
    FROM (

     <your UNION query here> 

    ) 
GROUP BY ConfInt, Conference 

Questo non è l'unico modo per ottenere il set di risultati, ma è la soluzione più rapida per soddisfare i requisiti specificati.

In alternativa, credo che queste query restituiranno risultati equivalenti:

Potremmo usare una subquery correlata nell'elenco SELECT per ottenere Quantità:

;WITH q AS 
     (SELECT B.ConfInt 
      , B.Conference 
      , SUM(o.NumberOfFansRequested) AS Ordered 
      , SUM(o.Qty_Fans_Approved) AS Approved 
      , SUM(o.Qty_Fans_PickedUp) AS PickedUp 
      FROM dbo.Conferences as B 
      LEFT 
      JOIN dbo.Cool_Fan_Order o ON o.Conference_ID = B.ConfInt 
     WHERE B.ProjectCool = 1 
     GROUP BY B.ConfInt, B.Conference 
    ) 
SELECT q.ConfInt 
     , q.Conference 
     , q.Ordered 
     , q.Approved 
     , q.PickedUp 
     , (SELECT SUM(v.Qty) 
      FROM dbo.Case_Table t 
      JOIN dbo.Case_Visit_Payments v ON v.Case_ID = t.Case_ID 
      WHERE t.Conference_ID = q.ConfInt 
      AND v.Item_ID = 15 
     ) AS Qty 
    FROM q 
    ORDER BY q.ConfInt, q.Conference 

Oppure, potremmo usare Operazione LEFT JOIN sulle due query, anziché UNION. (Sappiamo che la query che fa riferimento a Cool_Fan_Order può essere il lato SINISTRA del join esterno, poiché sappiamo che restituisce almeno altrettante righe dell'altra query. (Fondamentalmente, sappiamo che l'altra query non può restituire i valori di ConfInt e la Conferenza che non sono nella query Cool_Fan_Order.)

;WITH p AS 
     (SELECT A.ConfInt 
      , A.Conference 
      , SUM(v.Qty) AS Qty 
      FROM dbo.Conferences as A 
      JOIN dbo.Case_Table t ON t.Conference_ID = A.ConfInt 
      JOIN dbo.Case_Visit_Payments v ON v.Case_ID = t.Case_ID 
     WHERE A.ProjectCool = 1 
      AND v.Item_ID = 15 
     GROUP BY A.ConfInt, A.Conference 
    ) 
    , q AS 
     (SELECT B.ConfInt 
      , B.Conference 
      , SUM(o.NumberOfFansRequested) AS Ordered 
      , SUM(o.Qty_Fans_Approved) AS Approved 
      , SUM(o.Qty_Fans_PickedUp) AS PickedUp 
      FROM dbo.Conferences as B 
      LEFT 
      JOIN dbo.Cool_Fan_Order o ON B.ConfInt = o.Conference_ID 
     WHERE B.ProjectCool = 1 
     GROUP BY B.ConfInt, B.Conference 
    ) 
SELECT q.ConfInt 
     , q.Conference 
     , q.Ordered 
     , q.Approved 
     , q.PickedUp 
     , p.Qty 
    FROM q 
    LEFT 
    JOIN p ON p.ConfInt = q.ConfInt AND p.Conference = q.Conference 
    ORDER BY q.ConfInt, q.Conference 

la scelta tra questi tre (tutti restituiscono un gruppo di risultati equivalenti in tutte le conditons), si riduce a leggibilità e la manutenibilità, e le prestazioni. su grandi set di righe abbastanza potrebbero esserci alcune differenze di prestazioni osservabili tra le tre affermazioni

+0

La sub-query correlata ha fatto il trucco. Ha funzionato perfettamente. Grazie mille. –

+0

BTW: l'espressione di tabella comune non è richiesta per l'istruzione con la sottoquery correlata nell'elenco SELECT; il CTE potrebbe essere altrettanto facilmente sostituito con una vista in linea (nella clausola FROM), che è ciò che avremmo bisogno di fare se si trattasse di MySQL. – spencer7593

6

si potrebbe usare la query attuale come un subquery, utilizzare una funzione di aggregazione (Max o SUM) sui valori non duplicati e gruppo dalle colonne non aggregate

SELECT ConfInt, Conference, MAX(Ordered), MAX(Approved), MAX(PickedUp), MAX(Qty) 
FROM (<your actualQuery>) 
GROUP BY ConfInt, Conference. 
+0

Questo ha funzionato dopo che ho fatto un po 'di editing. Ho dovuto definire la tua selezione come tabella per farlo andare. SELECT x.ConfInt, x.Conference, MAX (x.Ordered) come ordinato, MAX (x.Approved) come approvato, MAX (x.PickedUp) come PickedUp, MAX (x.Qtà) come Qtà DA () x GROUP BY x.Conference, x.ConfInt –

0

Vorrei solo mettere il join in Cool_Fan_Order nella prima selezione e rimuovere il sindacato.

Questo restituisce gli stessi risultati?

select 
     A.ConfInt, 
     A.Conference, 
     sum(dbo.Cool_Fan_Order.NumberOfFansRequested) as Ordered, 
     sum(dbo.Cool_Fan_Order.Qty_Fans_Approved) as Approved, 
     sum(dbo.Cool_Fan_Order.Qty_Fans_PickedUp) as PickedUp, 
     sum(sub.Qty) as Qty 
    from 
     dbo.Conferences as A 
     left outer join 
     (
      select 
       c.ConfInt, 
       cvp.Qty 
      from dbo.Conferences c 
       inner join dbo.Case_Table ct 
        on a.confInt=ct.Conference_ID 
       inner join dbo.Case_Visit_Payments cvp 
        on ct.Case_ID=cvp.Case_ID 
      where cvp.Item_ID=15 
     ) sub 
      on a.ConfInt=sub.ConfInt 
     left outer join dbo.Cool_Fan_Order 
      on A.ConfInt = dbo.Cool_Fan_Order.Conference_ID 
    where 
     (
     A.ProjectCool = 1 
     ) 
    group by 
     A.Conference, 
     A.ConfInt 
+0

Questo non restituisce gli stessi risultati. Filtra solo i record trovati per Case_Visit_Payments. –

+0

Sì, ero troppo pigro. Quello che dovresti fare è spostare la logica dei casi in una sottoquery. Questo dovrebbe funzionare in teoria. – DForck42

+0

"In teoria non c'è differenza tra teoria e pratica, in pratica c'è". - Yogi Berra – spencer7593

Problemi correlati