2009-10-13 3 views
18

Ci sono due tabelle SQL:uno-a-molti query di selezione di tutti i genitori e singolo bambino superiore per ciascun genitore

Parents: 
+--+---------+ 
|id| text | 
+--+---------+ 
| 1| Blah | 
| 2| Blah2 | 
| 3| Blah3 | 
+--+---------+ 

Childs 
+--+------+-------+ 
|id|parent|feature| 
+--+------+-------+ 
| 1| 1 | 123 | 
| 2| 1 | 35 | 
| 3| 2 | 15 | 
+--+------+-------+ 

voglio selezionare con singola query ogni ferro sul tavolo genitori e per ognuno singola riga dalla tabella Childs con relazione "parent" - "id" valore e il più grande valore della colonna "feature". In questo esempio risultato dovrebbe essere:

+----+------+----+--------+---------+ 
|p.id|p.text|c.id|c.parent|c.feature| 
+----+------+----+--------+---------+ 
| 1 | Blah | 1 | 1 | 123 | 
| 2 | Blah2| 3 | 2 | 15 | 
| 3 | Blah3|null| null | null | 
+----+------+----+--------+---------+ 

dove p = tabella Padre e c = Tabella figlio

ho cercato di LEFT OUTER JOIN e GROUP BY, ma MSSQL espresso mi ha detto che query con GROUP BY richiedono funzioni di aggregazione su tutti i campi non raggruppati. E non voglio raggrupparli tutti, ma piuttosto selezionare la riga superiore (con l'ordine personalizzato).

Sono totalmente a corto di idee ...

risposta

18
select p.id, p.text, c.id, c.parent, c.feature 
from Parents p 
left join (select c1.id, c1.parent, c1.feature 
      from Childs c1 
      join (select p1.id, max(c2.feature) maxFeature 
        from Parents p1 
       left join Childs c2 on p1.id = c2.parent 
      group by p1.id) cf on c1.parent = cf.id 
           and c1.feature = cf.maxFeature) c 
on p.id = c.parent 
+0

Questo non restituirà solo il primo bambino ogni volta –

+0

Grazie. Risolto, ora lo sarà. – manji

+0

Funziona! Meraviglioso! – PiotrK

4

Questo dovrebbe funzionare:

SELECT p.id, p.text, c.id, c.parent,c.feature 
FROM parent p 
LEFT OUTER JOIN (SELECT TOP 1 child.id, 
           child.parent, 
           MAX(child.feature) 
        FROM child 
        WHERE child.parent = p.id 
        GROUP BY child.id, child.parent 
       ) c ON p.id = c.parent 
9

Utilizzando CTE (SQL Server 2005 +):

WITH max_feature AS (
    SELECT c.id, 
      c.parent, 
      MAX(c.feature) 'feature' 
    FROM CHILD c 
GROUP BY c.id, c.parent) 
    SELECT p.id, 
      p.text, 
      mf.id, 
      mf.parent, 
      mf.feature 
    FROM PARENT p 
LEFT JOIN max_feature mf ON mf.parent = p.id 

non CTE equivalente :

SELECT p.id, 
      p.text, 
      mf.id, 
      mf.parent, 
      mf.feature 
    FROM PARENT p 
LEFT JOIN (SELECT c.id, 
        c.parent, 
        MAX(c.feature) 'feature' 
      FROM CHILD c 
     GROUP BY c.id, c.parent) mf ON mf.parent = p.id 

Nella domanda mancano i dettagli per la gestione degli spareggi (quando 2 + CHILD.id valori hanno lo stesso valore di funzione). La risposta di Agent_9191 utilizza TOP 1, ma che prenderà il primo che viene restituito & non necessariamente quello che si desidera.

+1

Penso che raggruppare per (c.id, c.parent) è come restituire la tabella originale (Childs) poiché un genitore non può avere lo stesso figlio con 2 caratteristiche. – manji

2

La query di manji non gestisce i tie-break per la funzionalità massima. Ecco il mio metodo, che ho testato:

;WITH WithClause AS (SELECT p.id, p.text, 
     (SELECT TOP 1 c.id from childs c 
      where c.parent = p.id order by c.feature desc) 
     AS BestChildID 
    FROM Parents p) 
SELECT WithClause.id, WithClause.text, c.id, c.parent, c.feature 
FROM WithClause 
LEFT JOIN childs c on WithClause.BestChildID = c.id 
+0

Anche il metodo di OMG Ponies non funziona, ho provato e ottengo troppe righe con entrambi i suoi frammenti, come indicato da manji. – AndyH

1

Se è necessario iscriversi diverso da una colonna MAX e tutte le colonne descritte in un gruppo dalla chiusura di un prescelto nidificato, è possibile utilizzare una funzione di applicare. È la soluzione più semplice. Puoi anche usare l'operatore WITH. Ma sembra più difficile.

SELECT p.id, p.text, CHILD_ROW.ANY_COLLUMN 
FROM parent p 
OUTER APPLY (SELECT TOP 1 child.ANY_COLLUMN 
        FROM child 
        WHERE child.parent = p.id 
        ORDER BY child.feature DESC 
       ) CHILD_ROW 
Problemi correlati