11

tôi có các bảng sau:

tblPerson:Lấy các hồ sơ gần đây nhất trong một truy vấn

PersonID | Name 
--------------------- 
    1  | John Smith 
    2  | Jane Doe 
    3  | David Hoshi 

tblLocation:

LocationID | Timestamp | PersonID | X | Y | Z | More Columns... 
--------------------------------------------------------------- 
    40  | Jan. 1st |  3 | 0 | 0 | 0 | More Info... 
    41  | Jan. 2nd |  1 | 1 | 1 | 0 | More Info... 
    42  | Jan. 2nd |  3 | 2 | 2 | 2 | More Info... 
    43  | Jan. 3rd |  3 | 4 | 4 | 4 | More Info... 
    44  | Jan. 5th |  2 | 0 | 0 | 0 | More Info... 

tôi có thể tạo ra một truy vấn SQL mà được các hồ sơ Địa điểm mỗi Người như vậy:

SELECT LocationID, Timestamp, Name, X, Y, Z 
FROM tblLocation 
JOIN tblPerson 
ON tblLocation.PersonID = tblPerson.PersonID; 

để tạo ra các thông tin sau:

LocationID | Timestamp | Name  | X | Y | Z | 
-------------------------------------------------- 
    40  | Jan. 1st | David Hoshi | 0 | 0 | 0 | 
    41  | Jan. 2nd | John Smith | 1 | 1 | 0 | 
    42  | Jan. 2nd | David Hoshi | 2 | 2 | 2 | 
    43  | Jan. 3rd | David Hoshi | 4 | 4 | 4 | 
    44  | Jan. 5th | Jane Doe | 0 | 0 | 0 | 

Vấn đề của tôi là chúng tôi chỉ liên quan đến hồ sơ Vị trí gần đây nhất. Do đó, chúng tôi chỉ thực sự quan tâm đến các Hàng sau: LocationID 41, 43 và 44.

Câu hỏi là: Làm cách nào chúng tôi có thể truy vấn các bảng này để cung cấp cho chúng tôi dữ liệu gần đây nhất trên mỗi người nền tảng? Nhóm gì đặc biệt cần phải xảy ra để tạo ra kết quả mong muốn?

+0

bạn có thể đăng giải pháp cuối cùng plzz –

Trả lời

19

MySQL không có chức năng xếp hạng/phân tích/cửa sổ.

SELECT tl.locationid, tl.timestamp, tp.name, X, Y, Z 
    FROM tblPerson tp 
    JOIN tblLocation tl ON tl.personid = tp.personid 
    JOIN (SELECT t.personid, 
       MAX(t.timestamp) AS max_date 
      FROM tblLocation t 
     GROUP BY t.personid) x ON x.personid = tl.personid 
          AND x.max_date = tl.timestamp 

SQL Server 2005 + và Oracle 9i + hỗ trợ phân tích, vì vậy bạn có thể sử dụng:

SELECT x.locationid, x.timestamp, x.name, x.X, x.Y, x.Z 
    FROM (SELECT tl.locationid, tl.timestamp, tp.name, X, Y, Z, 
       ROW_NUMBER() OVER (PARTITION BY tp.name ORDER BY tl.timestamp DESC) AS rank 
      FROM tblPerson tp 
      JOIN tblLocation tl ON tl.personid = tp.personid) x 
WHERE x.rank = 1 

Sử dụng một biến để có được giống như chức năng ROW_NUMBER trên MySQL:

SELECT x.locationid, x.timestamp, x.name, x.X, x.Y, x.Z 
    FROM (SELECT tl.locationid, tl.timestamp, tp.name, X, Y, Z, 
       CASE 
       WHEN @name != t.name THEN 
        @rownum := 1 
       ELSE @rownum := @rownum + 1 
       END AS rank, 
       @name := tp.name 
      FROM tblLocation tl 
      JOIN tblPerson tp ON tp.personid = tl.personid 
      JOIN (SELECT @rownum := NULL, @name := '') r 
     ORDER BY tp.name, tl.timestamp DESC) x 
WHERE x.rank = 1 
+0

Cảm ơn OMG. Tôi lấy SQL Server 2005 và thay đổi nó một chút để tạo ra các kết quả mong muốn. –

3

Đây là câu hỏi 'tối đa mỗi nhóm' cổ điển xuất hiện trên Stack Overflow hầu như mỗi ngày. Có nhiều cách để giải quyết nó và bạn có thể tìm thấy các giải pháp mẫu bằng cách searching Stack Overflow. Dưới đây là một cách bạn có thể thực hiện trong MySQL:

SELECT 
    location.LocationId, 
    location.Timestamp, 
    person.Name, 
    location.X, 
    location.Y, 
    location.Z 
FROM (
    SELECT 
     LocationID, 
     @rn := CASE WHEN @prev_PersonID = PersonID 
        THEN @rn + 1 
        ELSE 1 
       END AS rn, 
     @prev_PersonID := PersonID 
    FROM (SELECT @prev_PersonID := NULL) vars, tblLocation 
    ORDER BY PersonID, Timestamp DESC 
) T1 
JOIN tblLocation location ON location.LocationID = T1.LocationId 
JOIN tblPerson person ON person.PersonID = location.PersonID 
WHERE rn = 1 
3

Như @ Mark Byers đề cập đến, vấn đề này xuất hiện thường xuyên trên Stack Overflow.

Đây là giải pháp tôi thường xuyên nhất đề nghị, đưa ra bảng của bạn:

SELECT p.*, l1.* 
FROM tblPerson p 
JOIN tblLocation l1 ON p.PersonID = l1.PersonID 
LEFT OUTER JOIN tblLocation l2 ON p.PersonID = l2.PersonID AND 
    (l1.timestamp < l2.timestamp OR l1.timestamp = l2.timestamp AND l1.LocationId < l2.LocationId) 
WHERE l2.LocationID IS NULL; 

Để xem ví dụ khác, hãy làm theo tag greatest-n-per-group, mà tôi thêm vào câu hỏi của bạn.

+0

Cảm ơn bạn đã thêm Thẻ cho tôi Bill! –

Các vấn đề liên quan