检索每组最新更改的记录

时间:2018-02-24 17:06:30

标签: mysql sql greatest-n-per-group

我有一张桌子locations

user | timestamp | state | other_data
-------------------------------------
1      100         1       some_data
1      200         1       some_data
1      300         0       some_data
1      400         0       some_data
2      100         0       some_data
2      200         0       some_data

这适用于位置跟踪应用。一个位置有两个state s(1个用于"用户在范围内" 0用于"用户超出范围")。

现在我想检索用户上次位置状态的更改。 user = 1

的示例
user | timestamp | state | other_data
-------------------------------------
1      300         0       some_data

因为这是第一个与"当前"具有相同state值的位置更新。 (timestamp 400)记录。

更高级别的描述:我希望向用户显示类似"您已经进入/超出范围,因为[时间戳]"

解决方案越快,当然越好

3 个答案:

答案 0 :(得分:2)

我会使用排名来排序行,然后选择排名第一行的min时间戳。

select user,min(timestamp) as timestamp,min(state) as state
from 
(select l.*,@rn:=case when @user=user and @state=state then @rn
                      when @user<>user then 1
                 else @rn+1 end as rnk
 ,@user:=user,@state:=state
 from locations l 
 cross join (select @rn:=0,@user:='',@state:='') r
 order by user,timestamp desc
) t
where rnk=1
group by user

答案 1 :(得分:1)

您可以使用相关子查询执行此操作:

select l.*
from locations l
where l.timestamp = (select max(l2.timestamp)
                     from locations l2
                     where l2.user = l.user
                    );

为了使其运作良好,您需要locations(user, timestamp)上的索引。

这可能比joingroup by方法更快。特别是,相关子查询可以使用索引,但整个表中的group by通常不会(在MySQL中)。

答案 2 :(得分:0)

据我所知,实现这一目标的唯一方法是销售加盟。有点像的东西;

function replacebackenddatabase() {
  var ui = SpreadsheetApp.getUi();

  var result = ui.prompt(
    'Ask a question...',
    ui.ButtonSet.OK_CANCEL);

  // Get the response...
  var button = result.getSelectedButton();
  var text = result.getResponseText();
  if (button == ui.Button.OK) {
    //If they clicked OK do something with 'text' variable

  } else if (button == ui.Button.CANCEL) {
    // If they clicked Cancel.

  } else if (button == ui.Button.CLOSE) {
    // If they closed the prompt

  }
}

语法适用于MsSQL,它应该转移到MySQL。可能必须指定列名而不是表。*