2009-12-23 34 views
15

Tôi đang tìm cách xử lý kịch bản sau đây. Tôi có một bảng cơ sở dữ liệu mà tôi cần phải trả về chỉ một bản ghi cho mỗi "id nhóm" được chứa trong bảng, hơn nữa bản ghi được chọn trong mỗi nhóm phải là người lâu đời nhất trong hộ gia đình.Truy vấn SQL chỉ trả lại 1 bản ghi cho mỗi ID nhóm

ID Group ID Name    Age 
1 134  John Bowers  37 
2 134  Kerri Bowers  33 
3 135  John Bowers  44 
4 135  Shannon Bowers  42 

Vì vậy, trong dữ liệu mẫu được cung cấp ở trên, tôi cần ID 1 và 3 trả về vì chúng là những người lâu đời nhất trong mỗi id nhóm.

Điều này đang được truy vấn dựa vào cơ sở dữ liệu SQL Server 2005.

+0

Nếu bạn muốn tên, bạn vẫn có cơ hội chọn> 1 hàng nếu bạn có> 1 người có tuổi già nhất. Bạn cũng nên thiết lập các tiêu chí về tên cần chọn trong trường hợp đó. –

+0

Điểm tốt Chris. Đã được cố gắng để simplifiy câu hỏi một chút, nhưng mà lá lỗ như thế này :-) Tôi thực sự có một lĩnh vực khác cho giới tính, vì vậy tôi đang tìm cách chọn nam lâu đời nhất trong một hộ gia đình. nếu có nam, thì là nữ lớn nhất. Trong trường hợp có hai nam giới trong cùng một hộ gia đình có cùng độ tuổi thì tôi chỉ cần chọn 1 trong số các hồ sơ. Điều này có thể được dựa trên một cái gì đó đơn giản như là người có số ID thấp nhất cho bộ ngắt kết nối. –

+1

Có một cuộc thảo luận tốt về loại vấn đề này trong phần 21.4, "Chức năng Extrema", trong cuốn sách tuyệt vời của Joe Celko "SQL cho Smarties". Nếu bạn đang đi để chạy vào bất cứ điều gì phức tạp hơn SELECT đơn giản và INSERTs, tôi rất khuyên bạn nên cuốn sách này. – shoover

Trả lời

21
SELECT t.* 
FROM (
     SELECT DISTINCT groupid 
     FROM mytable 
     ) mo 
CROSS APPLY 
     (
     SELECT TOP 1 * 
     FROM mytable mi 
     WHERE mi.groupid = mo.groupid 
     ORDER BY 
       age DESC 
     ) t 

hay này:

SELECT * 
FROM (
     SELECT *, ROW_NUMBER() OVER (PARTITION BY groupid ORDER BY age DESC) rn 
     FROM mytable 
     ) 
WHERE rn = 1 

này sẽ trở lại nhiều nhất là một bản ghi cho mỗi nhóm thậm chí trong trường hợp quan hệ.

Xem bài viết này trong blog của tôi để so sánh hiệu suất của cả hai phương pháp:

+0

+1: Vâng, quên tuyên bố từ chối trách nhiệm của tôi về các mối quan hệ. Quá bận rộn chiến đấu cháy. –

+0

Cảm ơn Quassnoi. Tôi đã có thể thêm cột giới tính trong phần bổ sung vào cột tuổi trong mệnh đề ORDER của bạn và nhận được kết quả mà tôi đang tìm kiếm! (Cột giới tính chỉ được thảo luận trong một bình luận sau câu hỏi ban đầu của tôi) Giải pháp của bạn là hoàn hảo và thích nghi! –

+0

Câu hỏi tiếp theo. Chúng sẽ được chạy với 175 triệu bản ghi. Là một hoặc các truy vấn khác hiệu quả hơn? –

0
SELECT GroupID, Name, Age 
FROM table 
INNER JOIN 
(
SELECT GroupID, MAX(Age) AS OLDEST 
FROM table 
) AS OLDESTPEOPLE 
ON 
table.GroupID = OLDESTPEOPLE.GroupID 
AND 
table.Age = OLDESTPEOPLE.OLDEST 
3

Sử dụng:

SELECT DISTINCT 
     t.groupid, 
     t.name 
    FROM TABLE t 
    JOIN (SELECT t.groupid, 
       MAX(t.age) 'max_age' 
      FROM TABLE t 
     GROUP BY t.groupid) x ON x.groupid = t.groupid 
          AND x.max_age = t.age 

Vì vậy, những gì nếu có 2+ người cùng độ tuổi cho một nhóm? Sẽ tốt hơn nếu bạn lưu trữ ngày sinh thay vì tuổi - bạn luôn có thể tính ngày sinh cho bản trình bày.

+0

Hãy coi chừng mối quan hệ! – Quassnoi

0

Hãy thử điều này (giả sử Nhóm là từ đồng nghĩa với gia)

Select * From Table t 
Where Age = (Select Max(Age) 
      From Table 
      Where GroupId = t.GroupId) 

Nếu có hai hoặc nhiều "lâu đời nhất" người dân ở một số hộ gia đình (Họ tất cả đều cùng tuổi và không có ai khác cũ hơn), sau đó điều này sẽ trả về tất cả chúng, không chỉ là ngẫu nhiên.

Nếu đây là vấn đề, bạn cần phải thêm một truy vấn con khác để trả lại giá trị khóa tùy ý cho một người trong tập hợp đó.

Select * From Table t 
Where Id = 
    (Select Max(Id) Fom Table 
    Where GroupId = t.GroupId 
     And Age = 
     (Select(Max(Age) From Table 
      Where GroupId = t.GroupId)) 
Các vấn đề liên quan