2009-10-13 7 views
18

Il y a deux tables SQL:un à plusieurs requêtes sélection de tous les parents et les enfants haut unique pour chaque parent

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

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

Je veux sélectionner avec seule requête chaque ligne de la table des parents et pour chaque une seule rangée de la table Childs avec la valeur "parent" - "id" et la plus grande valeur de la colonne "feature". Dans cet exemple résultat devrait être:

+----+------+----+--------+---------+ 
|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 | 
+----+------+----+--------+---------+ 

p = table parent et c = table enfant

moi avons essayé de LEFT OUTER JOIN et GROUP BY mais MSSQL express m'a dit que requête avec GROUP BY nécessitent des fonctions d'agrégation sur tous les champs non-Groupped. Et je ne veux pas les regrouper tous, mais plutôt sélectionner la rangée supérieure (avec commande personnalisée).

Je suis tout à fait d'idées ...

Répondre

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

Cela ne retournera pas seulement le premier enfant à chaque fois –

+0

Merci. Fixe, maintenant ça va. – manji

+0

Ça marche! Formidable! – PiotrK

4

Cela devrait fonctionner:

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

utilisant 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 

équivalent non CTE :

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 

Votre question manque de détails pour la gestion des disjoncteurs (lorsque 2+ CHILD.id valeurs ont la même valeur de caractéristique). La réponse de Agent_9191 utilise TOP 1, mais cela prendra le premier qui est retourné & pas nécessairement celui que vous voulez.

+1

Je pense que grouper par (c.id, c.parent) revient à retourner la table d'origine (Childs) car un parent ne peut pas avoir le même enfant avec 2 caractéristiques. – manji

2

La requête de manji ne gère pas les tie-break pour la fonctionnalité max. Voici ma méthode, que je l'ai testé:

;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

OMG Les poneys ne fonctionnent pas non plus, j'ai testé, et j'ai trop de lignes avec les deux extraits, comme manji l'a indiqué. – AndyH

1

Si vous devez être membre différent d'une colonne MAX et toutes les colonnes décrites dans un groupe par la fermeture d'une sélection imbriquée, vous pouvez utiliser une fonction de transformation. C'est la solution la plus simple. Vous pouvez également utiliser l'opérateur WITH. Mais ça a l'air plus dur.

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 
Questions connexes