在sqlite中计算相邻记录

时间:2014-06-25 09:35:39

标签: sql sqlite

我有下表

ID  location date
--  -------- -----
01  loc#1    10-06-2014
05  loc#1    11-06-2014
06  loc#2    13-06-2014
08  loc#2    14-06-2014
10  loc#2    15-06-2014
14  loc#1    16-06-2014
17  loc#1    17-06-2014
20  loc#1    18-06-2014

我需要的是获取每个位置以及按ID排序提及此位置的相邻记录的数量

location count(location)
-------- --------------- 
loc#1    2 
loc#2    3 
loc#1    3

使用count + group by的问题是,它计算相同位置的所有记录,不仅是相邻位置,还输出一组唯一的位置

select location, count(location) from table group by location order by ID

location count(location)
-------- --------------- 
loc#1    5
loc#2    3

任何想法如何获得正确的查询?因为我不想以编程方式进行编程,因为我正在使用iPhone上的数千条记录,这会产生性能问题

3 个答案:

答案 0 :(得分:1)

select minAdjLoc.ID, max(minAdjLoc.location) 'Loc', count(distinct adjLocs.ID) 'Count' 
from test minAdjLoc              -- Minimum record in each adjacent group
inner join test adjLocs          -- All adjacent record, including self
    on adjLocs.location = minAdjLoc.location
    and adjLocs.ID >= minAdjLoc.ID
left join test intruder          -- Possible intruder with different location
    on intruder.location <> minAdjLoc.location
    and intruder.ID > minAdjLoc.ID
    and intruder.ID < adjLocs.ID
left join test lowerThanMin      -- Possible record lower than minAdjLoc
    on lowerThanMin.ID < minAdjLoc.ID
    and lowerThanMin.location <> minAdjLoc.location
left join test lowerIntruder
    on (lowerThanMin.ID is null or lowerThanMin.ID < lowerIntruder.ID)
    and lowerIntruder.ID < minAdjLoc.ID
    and lowerIntruder.location = minAdjLoc.location
    where intruder.ID is null    -- There can't be any record with a different location inside the group
    and lowerIntruder.ID is null -- Ensure minAdjLoc is in fact the record with minimum ID
group by minAdjLoc.ID            --The minimum ID of the adjacent group is unique
order by minAdjLoc.ID

答案 1 :(得分:1)

我认为这可以起作用

SELECT location, COUNT(*)
  FROM (SELECT CASE WHEN t1.location <> (SELECT location FROM t WHERE id = (SELECT MAX(id) FROM t WHERE id < t1.id))
                    THEN t1.id
                    WHEN (SELECT MIN(id) FROM t WHERE id > (SELECT MAX(id) FROM t WHERE location <> t1.location AND id < t1.id)) IS NULL
                    THEN (SELECT MIN(id) FROM t)
                    ELSE (SELECT MIN(id) FROM t WHERE id > (SELECT MAX(id) FROM t WHERE location <> t1.location AND id < t1.id))
                    END         AS mark,
                    t1.id       AS id,
                    t1.location AS location
          FROM t AS t1)
  GROUP BY mark, location
;

答案 2 :(得分:0)

@JoséMargaçaLopes 我还编辑了你的第一个答案是喜欢这个正在运作的

select minAdjLoc.ID, max(minAdjLoc.location) 'Loc', count(adjLocs.ID) 'Count' 
from test minAdjLoc -- Minimum record in each adjacent group 
inner join test adjLocs -- All adjacent record, including self 
on adjLocs.location = minAdjLoc.location 
and adjLocs.ID >= minAdjLoc.ID 
left join test intruder -- Possible intruder with different location 
on intruder.location <> minAdjLoc.location 
and intruder.ID > minAdjLoc.ID 
and intruder.ID < adjLocs.ID 
left join test lowerThanMin -- Possible record lower than minAdjLoc 
on lowerThanMin.ID = (select ID from test where ID < minAdjLoc.ID) -- ** my modificatoin **
and lowerThanMin.location = minAdjLoc.location 
where intruder.ID is null -- There can't be any record with a different location inside the group 
and lowerThanMin.ID is null -- This is to ensure minAdjLoc is in fact the record with minimum ID 
group by minAdjLoc.ID --The minimum ID of the adjacent group is unique