2009-10-13 19 views
18

Hay dos tablas SQL:uno-a-muchos consulta seleccionando todos los padres y el niño solo tapa para cada padre

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

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

Quiero seleccionar la consulta única cada fila de la tabla de los padres y para cada una sola fila de la tabla de Childs con relación "padre" - valor "id" y el mayor valor de columna "característica". En este ejemplo resultado debe ser:

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

Donde p = tabla primaria y c = Mesa de niño

yo tratamos de combinación externa izquierda y GROUP BY, pero MSSQL expreso me dijeron que consulta con GROUP BY requieren funciones de agregado en cada campo no agrupado. Y no quiero Agruparlos a todos, sino seleccionar la fila superior (con pedidos personalizados).

estoy totalmente fuera de las ideas ...

Respuesta

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

Esto no volverá solo al mejor niño cada vez –

+0

Gracias. Corregido, ahora lo hará. – manji

+0

¡Está funcionando! ¡Maravilloso! – PiotrK

4

Esto debería funcionar:

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

Usando 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 

no 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 

Su pregunta carece de detalles para manejar los tie breakers (cuando 2+ CHILD.id valores tienen el mismo valor de característica). La respuesta de Agent_9191 usa TOP 1, pero eso tomará el primero que se devuelve & no necesariamente el que desea.

+1

Creo que agrupar por (c.id, c.parent) es como devolver la tabla original (Childs) ya que un padre no puede tener el mismo hijo con 2 funciones. – manji

2

La consulta de manji no maneja los tie-breakers para la característica máxima. Aquí está mi método, que he probado:

;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

El método OMG Ponies tampoco funciona, probé, y recibí demasiadas filas con sus dos fragmentos, como lo indicó manji. – AndyH

1

Si necesita unirse a una columna diferente de MAX y las columnas descritas en un grupo por el cierre de un selecto anidado, puede utilizar una función de aplicar. Es la solución más simple. También puede usar el operador CON. Pero eso parece más difícil.

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 
Cuestiones relacionadas