2009-07-16 31 views
60

Tôi đang cố gắng nhận dấu thời gian ip, người dùng và dấu thời gian gần nhất từ ​​bảng có thể chứa cả ip hiện tại cho người dùng và một hoặc nhiều từ trước ips. Tôi muốn một hàng cho mỗi người dùng chứa ip gần nhất và dấu thời gian được liên kết. Vì vậy, nếu một bảng trông như thế này:Truy vấn SQL để nhận hàng gần đây nhất cho từng trường hợp của một khóa cụ thể

username  | ip  | time_stamp 
--------------|----------|-------------- 
ted   | 1.2.3.4 | 10 
jerry   | 5.6.6.7 | 12 
ted   | 8.8.8.8 | 30 

tôi mong đợi kết quả của truy vấn là:

jerry | 5.6.6.7 | 12 
ted  | 8.8.8.8 | 30 

Tôi có thể làm điều này trong một truy vấn sql đơn? Trong trường hợp nó quan trọng, DBMS là Postgresql.

Trả lời

90

Hãy thử điều này:

Select u.[username] 
     ,u.[ip] 
     ,q.[time_stamp] 
From [users] As u 
Inner Join (
    Select [username] 
      ,max(time_stamp) as [time_stamp] 
    From [users] 
    Group By [username]) As [q] 
On u.username = q.username 
And u.time_stamp = q.time_stamp 
+0

Tôi đã đi đúng hướng nhưng tôi không thể tham gia đúng. Điều này đã làm các trick. Cảm ơn! – alanc10n

+2

Tính năng này có hoạt động trong SQL Server không? Đã thử chính xác điều tương tự trên dữ liệu tương tự nhưng tôi nhận được một hàng cho mỗi "ip" cùng với chỉ dấu thời gian gần đây nhất. – tcash21

+0

Được sử dụng đối với bảng HANA, điều này tạo ra nhiều hàng trong đó 1 được mong đợi. HANA có rất nhiều thứ không giống như hầu hết các công cụ SQL phổ biến. –

7

Something như thế này:

select * 
from User U1 
where time_stamp = (
    select max(time_stamp) 
    from User 
    where username = U1.username) 

nên làm điều đó.

+0

Điều đó sẽ hoạt động nếu 'time_stamp' sẽ là duy nhất và bạn không thể giả định điều đó. – Nux

3

Cả hai câu trả lời ở trên giả định rằng bạn chỉ có một hàng cho mỗi người dùng và time_stamp. Tùy thuộc vào ứng dụng và độ chi tiết của time_stamp của bạn, đây có thể không phải là một giả định hợp lệ. Nếu bạn cần xử lý các mối quan hệ của time_stamp cho một người dùng cụ thể, bạn cần mở rộng một trong các câu trả lời được đưa ra ở trên.

Để viết điều này trong một truy vấn sẽ yêu cầu một truy vấn con lồng nhau khác - mọi thứ sẽ bắt đầu trở nên lộn xộn hơn và hiệu suất có thể bị ảnh hưởng.

Tôi rất muốn có thêm nhận xét này làm nhận xét nhưng tôi chưa có 50 danh tiếng nên xin lỗi vì đã đăng câu trả lời mới!

+5

"Cả hai điều trên ..." không phải là cách hay để bắt đầu câu trả lời. Làm thế nào để tôi biết nếu các câu trả lời ở trên đây là những câu hỏi mà bạn đang đề cập đến? Câu trả lời có thể xuất hiện theo thứ tự khác nhau dựa trên điểm số của họ. –

+6

Rob, tôi không nghĩ rằng bạn đang nói cho anh ta một cái gì đó anh ta không biết.Anh ta không bình luận và câu trả lời anh ta nói đến rõ ràng là thiếu sót. Điều gì quan trọng hơn, truyền bá kiến ​​thức hoặc phê bình nơi văn bản được đặt? – cruskai239

0

Tôi đã sử dụng điều này vì tôi trả lại kết quả từ một bảng khác. Mặc dù tôi đang cố gắng tránh tham gia lồng nhau nếu nó giúp w/một bước ít hơn. Oh well. Nó trả về cùng một thứ.

select 
users.userid 
, lastIP.IP 
, lastIP.maxdate 

from users 

inner join (
    select userid, IP, datetime 
    from IPAddresses 
    inner join (
     select userid, max(datetime) as maxdate 
     from IPAddresses 
     group by userid 
     ) maxIP on IPAddresses.datetime = maxIP.maxdate and IPAddresses.userid = maxIP.userid 
    ) as lastIP on users.userid = lastIP.userid 
+0

Tôi nghĩ đây là câu trả lời cho câu trả lời của người dùng trên – jawz101

29

giải pháp thanh lịch đẹp với chức năng cửa sổ ROW_NUMBER (được hỗ trợ bởi PostgreSQL - xem trong SQL Fiddle):

SELECT username, ip, time_stamp FROM (
SELECT username, ip, time_stamp, 
    ROW_NUMBER() OVER (PARTITION BY username ORDER BY time_stamp DESC) rn 
FROM Users 
) tmp WHERE rn = 1; 
+2

Đây là câu trả lời hay nhất, vì nó không liên quan đến việc tham gia vào một truy vấn lồng nhau. Chỉ có vấn đề là nó cần phải bao gồm [ip] trong khóa cũng như tên người dùng cho mỗi câu hỏi. – dashnick

1

Không thể đăng bình luận nào, nhưng câu trả lời @Cristi S của một công trình xử đối với tôi .

Trong trường hợp của tôi, tôi chỉ cần giữ lại 3 bản ghi gần đây nhất trong Lowest_Offers cho tất cả product_ids.

Cần phải làm lại SQL để xóa - nghĩ rằng điều này sẽ ổn, nhưng cú pháp là sai.

DELETE from (
SELECT product_id, id, date_checked, 
    ROW_NUMBER() OVER (PARTITION BY product_id ORDER BY date_checked DESC) rn 
FROM lowest_offers 
) tmp WHERE > 3; 
+0

Corrected SQL: DELETE FROM Lowest_Offer WHERE id trong ( \t SELECT id TỪ \t ( \t \t CHỌN product_id, id, date_checked, \t \t ROW_NUMBER() OVER (PARTITION BY TỰ product_id THEO date_checked DESC) rn \t \t FROM Lowest_Offer \t) tmp WHERE rn> 3 ) – err1

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