2009-10-13 29 views
18

Có hai bảng SQL:one-to-many truy vấn chọn tất cả các bậc cha mẹ và con đầu duy nhất cho mỗi phụ huynh

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

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

Tôi muốn chọn với truy vấn duy nhất mỗi dòng từ bảng phụ huynh và cho mỗi một hàng duy nhất từ bảng Childs có quan hệ "parent" - giá trị "id" và giá trị cột "feature" lớn nhất. Trong ví dụ này kết quả sẽ là:

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

đâu p = bảng mẹ và c = bảng Child

Tôi cố gắng để LEFT OUTER JOIN và GROUP BY nhưng MSSQL nhanh nói với tôi rằng truy vấn với GROUP BY yêu cầu chức năng tổng hợp trên mọi trường không được Groupped. Và tôi không muốn Nhóm tất cả, mà là chọn hàng trên cùng (với thứ tự tùy chỉnh).

Tôi hoàn toàn ra khỏi ý tưởng ...

Trả lời

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

Điều này sẽ không chỉ trả lại con đầu mỗi lần –

+0

Cảm ơn. Cố định, bây giờ nó sẽ. – manji

+0

Nó hoạt động! Tuyệt vời! – PiotrK

4

này nên làm việc:

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

Sử dụng 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 tương đương :

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 

Câu hỏi của bạn thiếu chi tiết để xử lý bộ ngắt kết nối (khi 2+ CHILD.id giá trị có cùng giá trị tính năng). Câu trả lời của Agent_9191 sử dụng TOP 1, nhưng đó sẽ là câu trả lời đầu tiên được trả về & không nhất thiết phải là thứ bạn muốn.

+1

Tôi nghĩ rằng việc nhóm theo (c.id, c.parent) giống như trả lại bảng gốc (Childs) vì cha mẹ không thể có cùng một con với 2 tính năng. – manji

2

truy vấn của manji không xử lý bộ ngắt kết nối cho tính năng tối đa. Đây là phương pháp của tôi, mà tôi đã thử nghiệm:

;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

Phương pháp của OMG Ponies cũng không hoạt động, tôi đã thử nghiệm và tôi nhận được quá nhiều hàng với cả hai đoạn mã của mình, như manji đã chỉ ra. – AndyH

1

Nếu bạn cần tham gia khác với cột MAX và bất kỳ cột nào được mô tả trong nhóm bằng cách đóng chọn lồng nhau, bạn có thể sử dụng hàm ÁP DỤNG. Đây là giải pháp đơn giản nhất. Bạn cũng có thể sử dụng toán tử WITH. Nhưng trông khó hơn.

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 
Các vấn đề liên quan