2009-07-16 3 views
60

Я пытаюсь получить ip, user и самую последнюю метку времени из таблицы, которая может содержать как текущий ip для пользователя, так и один или несколько предыдущих изобр. Мне нужна одна строка для каждого пользователя, содержащего самый последний ip и связанный с ним временной штамп. Так что, если таблица выглядит следующим образом:SQL-запрос для получения последней строки для каждого экземпляра заданного ключа

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

Я бы ожидать, что результат запроса будет:

jerry | 5.6.6.7 | 12 
ted  | 8.8.8.8 | 30 

Могу ли я сделать это в одном запросе SQL? В случае, если это имеет значение, СУБД - Postgresql.

ответ

90

Попробуйте это:

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

Я был на правильном пути, но я не мог получить право на участие. Это сделал трюк. Благодаря! – alanc10n

+2

Это работает в SQL Server? Пробовал то же самое на похожих данных, но я получаю строку для каждого «ip» вместе с самой последней меткой времени. – tcash21

+0

Используется против таблицы HANA, это привело к появлению нескольких строк, где ожидалось 1. У HANA есть много вещей, которые не совпадают с большинством популярных движков SQL. –

7

Что-то вроде этого:

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

должен сделать это.

+0

Это будет работать, если 'time_stamp' будет уникальным, и вы не можете этого допустить. – Nux

3

В обоих приведенных выше ответах предполагается, что у вас есть только одна строка для каждого пользователя и time_stamp. В зависимости от приложения и детализации вашего time_stamp это может быть недействительным. Если вам нужно иметь дело с привязками time_stamp для данного пользователя, вам нужно будет расширить один из ответов, приведенных выше.

Чтобы написать это в одном запросе, потребуется другой вложенный подзапрос - все начнет становиться более грязным, и производительность может пострадать.

Я бы с удовольствием добавил это в качестве комментария, но у меня пока нет репутации 50, так жаль, что разместил в качестве нового ответа!

+5

«Оба вышеуказанного ...» - не лучший способ начать ответ. Как я могу узнать, соответствуют ли ответы выше, о которых вы говорите? Ответы могут появляться в другом порядке, основываясь на их оценке. –

+6

Роб, я не думаю, что ты ему рассказываешь то, чего он не знает.Он НЕ МОЖЕТ комментировать, и ответы, на которые он ссылался, были явно ошибочными. Что еще важнее, распространение знаний или критика, где был размещен текст? – cruskai239

0

Я использовал это, потому что я возвращаю результаты из другой таблицы. Хотя я пытаюсь избежать вложенного соединения, если он помогает с меньшим шагом. Ну что ж. Он возвращает то же самое.

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

Я думаю, что это ответ для ответа пользователя выше. – jawz101

29

Nice элегантное решение с функцией окна ROW_NUMBER (поддерживается PostgreSQL - см в 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

Это лучший ответ, так как он не включает соединение по вложенному запросу. Единственная проблема заключается в том, что он должен включать в себя [ip] в ключе, а также имя пользователя в вопросе. – dashnick

1

не могут оставлять комментарии пока нет, но ответ @Cristi S работает лакомство для меня ,

В моем сценарии мне нужно было сохранить только последние 3 записи в Lowest_Offers для всех product_ids.

Необходимо переделать свой SQL-код для удаления - подумал, что это будет нормально, но синтаксис неверен.

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

исправлена ​​в SQL: DELETE FROM Lowest_Offer WHERE ID в ( \t SELECT, идентификатор из \t ( \t \t ВЫБОР product_id, ID, date_checked, \t \t ROW_NUMBER() OVER (PARTITION BY product_id ORDER BY date_checked DESC) р-н \t \t FROM Lowest_Offer \t) tmp WHERE rn> 3 ) – err1