2009-10-13 2 views
18

두 SQL 테이블이 있습니다일대 각 부모에 대한 모든 부모와 단일 상단의 아이를 선택 쿼리

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

Childs 
+--+------+-------+ 
|id|parent|feature| 
+--+------+-------+ 
| 1| 1 | 123 | 
| 2| 1 | 35 | 
| 3| 2 | 15 | 
+--+------+-------+ 
내가 단일 쿼리와 부모 테이블에서 모든 행을 선택합니다

각각 하나의 행은 관계 "부모"- "id"값과 가장 큰 "기능"열 값이있는 차일드 테이블에서. 이 예에서 결과가 있어야한다 : P = 부모 테이블과 C = 자식 테이블

내가 LEFT OUTER에 노력

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

은 가입 및 GROUP BY하지만 MSSQL Express는 GROUP BY와 해당 쿼리가 집계 함수를 필요로 나에게 말했다 Groupped가 아닌 모든 필드에 표시됩니다. 모든 항목을 그룹화하지 않고 맨 위 행을 선택합니다 (맞춤 주문). 나는 완전히 밖으로 아이디어입니다

...

답변

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

이 때마다 최고 어린이가 반환되지 않습니다. –

+0

감사합니다. 고정되어 이제 가능할 것입니다. – manji

+0

작동 중! 훌륭한! – PiotrK

4

이 작동합니다 :

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 

비 CTE에 해당 : CTE (SQL 서버 2005 +)를 사용하여

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

:

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 

타이 브레이커 (2+ CHILD.id 값이 동일한 기능 값을 갖는 경우)를 처리하는 데 대한 세부 사항이 부족합니다. Agent_9191의 응답은 TOP 1을 사용하지만, 그 중 첫 번째 값은 &으로 반환됩니다.

+1

(c.id, c.parent)로 그룹화하는 것은 부모가 2 개의 기능을 가진 동일한 하위를 가질 수 없기 때문에 원래 테이블 (차일 즈)을 반환하는 것과 같다고 생각합니다. – manji

2

manji의 쿼리는 최대 기능의 타이 브레이커를 처리하지 않습니다.

;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 Ponies의 방법도 작동하지 않으며 테스트를 마쳤습니다. manji가 지시했듯이 두 스 니펫 모두에 너무 많은 행이 표시됩니다. – AndyH

1

당신은 MAX 열 및 중첩 된 선택의 폐쇄하여 그룹에 설명 된 모든 컬럼에서 다른 가입해야하는 경우, 당신은이 기능을 적용 사용할 수 있습니다 여기에 내가 테스트 한 나의 방법이다. 가장 간단한 솔루션입니다. WITH 연산자도 사용할 수 있습니다. 하지만 좀 더 세게 보입니다.

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