HiveBrain v1.2.0
Get Started
← Back to all entries
patternsqlMinor

find the beginning and ending values of sequential runs

Submitted by: @import:stackexchange-dba··
0
Viewed 0 times
thevaluessequentialbeginningfindandendingruns

Problem

This article does the inverse of what I need: Find which numbers in [1, 161] are not in the result set?

Given the sample data they used:

mysql> CREATE TABLE wp_blogs
    -> (
    ->   blog_id INTEGER
    -> );

mysql> insert into wp_blogs values(1);
mysql> insert into wp_blogs values(2);
mysql> insert into wp_blogs values(4);
mysql> insert into wp_blogs values(6);
mysql> insert into wp_blogs values(7);
mysql> insert into wp_blogs values(8);
mysql> insert into wp_blogs values(10);


this query answers the question, "What are the gaps?":

mysql> SELECT a.blog_id+1 AS start, MIN(b.blog_id) - 1 AS end
    ->     FROM wp_blogs AS a, wp_blogs AS b
    ->     WHERE a.blog_id      GROUP BY a.blog_id
    ->     HAVING start < MIN(b.blog_id);

+-------+------+
| start | end  |
+-------+------+
|     3 |    3 |
|     5 |    5 |
|     9 |    9 |
+-------+------+


What I want to know is what are the islands?
I would like to see output like this:

+-------+------+  
| start | end  |  
+-------+------+  
|     1 |    2 |  
|     4 |    4 |  
|     6 |    8 |  
|    10 |   10 |  
+-------+------+


but I can't quite figure out the query to do so. I am using MySQL 5.6.

Anyone have a solution?

Solution

To keep all the state information with the current row to avoid having conditions you can so something like:

SELECT start, max(end) FROM (
    SELECT 
        CASE WHEN blog_id = @prev + 1 THEN @start:=@start ELSE @start:=blog_id END AS start, 
        blog_id AS end,  
        @prev:=blog_id 
    FROM (SELECT @prev:=NULL, @start:=NULL) AS vars
    JOIN wp_blogs
) a 
GROUP BY start;

+---------+------------+
|   start |   max(end) |
|---------+------------|
|       1 |          2 |
|       4 |          4 |
|       6 |          8 |
|      10 |         10 |
+---------+------------+
4 rows in set
Time: 0.003s

Code Snippets

SELECT start, max(end) FROM (
    SELECT 
        CASE WHEN blog_id = @prev + 1 THEN @start:=@start ELSE @start:=blog_id END AS start, 
        blog_id AS end,  
        @prev:=blog_id 
    FROM (SELECT @prev:=NULL, @start:=NULL) AS vars
    JOIN wp_blogs
) a 
GROUP BY start;

+---------+------------+
|   start |   max(end) |
|---------+------------|
|       1 |          2 |
|       4 |          4 |
|       6 |          8 |
|      10 |         10 |
+---------+------------+
4 rows in set
Time: 0.003s

Context

StackExchange Database Administrators Q#138071, answer score: 4

Revisions (0)

No revisions yet.