Reputation: 5852
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
i.e.
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
i.e.
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
Upvotes: 1
Views: 171
Reputation: 149
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
Upvotes: 1
Reputation: 367
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
;
Upvotes: 1
Reputation: 5852
@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
Upvotes: 0