从子查询保留顺序(使用GROUP BY和ORDER BY)

时间:2016-03-10 17:51:28

标签: sql postgresql group-by sql-order-by

我正在使用智能手机从加速计收集数据,然后将其保存在服务器的postgresql数据库中。基本上,每次我读取加速度计时,我都会保存智能手机当前的纬度/经度,以及它发生的时间戳。

现在,我想从数据库中读取每个不同位置(纬度/经度)的顺序与保存顺序(按时间戳排序)。而且我想知道每个位置有多少读数重复。

让我举个例子来解释一下。考虑我的数据库中有以下表格:

+------------+------------+-----------+
| latitude   | longitude  | timestamp |
+------------+------------+-----------+
| 43.1784771 | -8.5956853 | 930560045 |
| 43.1784771 | -8.5956853 | 930560054 |
| 41.2784813 | -7.5956853 | 930560063 |
| 42.1786173 | -8.5951757 | 930560072 |
| 42.1786173 | -8.5951757 | 930560082 |
+------------+------------+-----------|

请注意,我有按时间戳排序的元素,并且我有2个重复的位置。所以,我想查询数据库以查看重复的位置并得到以下结果:

+------------+------------+-------+
| latitude   | longitude  | count |
+------------+------------+-------+
| 43.1784771 | -8.5956853 | 2     |
| 41.2784813 | -7.5956853 | 1     |
| 42.1786173 | -8.5951757 | 2     |
+------------+------------+-------|

问题在于我希望将元素排序为原始表(按时间戳排序)。 我正在尝试以下查询,但它不起作用,因为子查询中的顺序并不重要:

SELECT latitude, longitude, count(*)
FROM 
    (SELECT latitude, longitude, timestamp FROM table ORDER BY timestamp asc) subquery1
GROUP BY latitude, longitude

我一直在寻找StackOverflow的答案,最接近的是这个:Is order in a subquery guaranteed to be preserved? 但是,它不适用于我的情况,因为我需要" group by"条款。有人可以帮帮我吗?

3 个答案:

答案 0 :(得分:3)

SELECT 
latitude, 
longitude, 
count(1) as "Count", 
min(timestamp) as "Start",
max(timestamp) as "End"

FROM table 
GROUP BY latitude, longitude
ORDER BY min(timestamp) asc

答案 1 :(得分:1)

create or replace function foo(
  out latitude numeric, 
  out longitude numeric,
  out cnt int,
  out start_time numeric,
  out end_time numeric
) returns setof record as $$
declare
  c record;
  p record;
  i int := 1;
begin
  select null into p;
  for c in (select * from table order by timestamp) 
  loop
    if p is null then
      start_time := c.timestamp;
    elsif p.latitude <> c.latitude and p.longitude <> c.longitude then
      latitude := p.latitude; 
      longitude := p.longitude;
      cnt := i;
      end_time := p.timestamp;
      return next;
      i := 1;
      start_time := p.timestamp;
    else
      i := i + 1;
    end if;
    p := c;
  end loop;
  if p.latitude = c.latitude and p.longitude = c.longitude then
    latitude := p.latitude; 
    longitude := p.longitude;
    cnt := i;
    end_time := p.timestamp;
    return next;
  end if;
  return;
end; $$ immutable language plpgsql;

用法:

select * from foo();

作为一点奖励,它还为每个系列提供开始/结束时间戳。

答案 2 :(得分:0)

子查询不会保留排序,但可以为array_agg操作定义它,我们可以使用它来确定更广泛的排序。尝试以下示例:

SELECT latitude, longitude, count(*), (array_agg(timestamp order by timestamp))[1] as first_time
FROM table GROUP BY latitude, longitude;

在OP的情况下,min(timestamp)可能更简单,但是如果排序更复杂,这可能是一个更整洁的选择。