简体   繁体   中英

Count adjacent records in sqlite

I have the following table

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

what i need is to get each location and the number of adjacent records that this location is mentioned on ordered by ID

ie

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

the problem with using count + group by is that it counts all records for same location not only the adjacent and output a unique set of locations

ie

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

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

any idea how to get the correct query? as I don't want to make it programmatically as i'm working with multiple thousands of records on iPhone which will produce a performance problem

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

I think this can work

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
;

@José Margaça Lopes I also edited your first answer be to like this which is working

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 

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM