Question

I'm trying to figure out a way of identifying a "run" of results (successive rows, in order) that meet some condition. Currently, I'm ordering a result set, and scanning by eye for particular patterns. Here's an example:

SELECT the_date, name
FROM orders
WHERE 
    the_date BETWEEN 
        to_date('2013-09-18',..) AND 
        to_date('2013-09-22', ..)
ORDER BY the_date

--------------------------------------
the_date            | name
--------------------------------------
2013-09-18 00:00:01 | John
--------------------------------------
2013-09-19 00:00:01 | James
--------------------------------------
2013-09-20 00:00:01 | John
--------------------------------------
2013-09-20 00:00:02 | John
--------------------------------------
2013-09-20 00:00:03 | John
--------------------------------------
2013-09-20 00:00:04 | John
--------------------------------------
2013-09-21 16:00:01 | Jennifer
--------------------------------------

What I want to extract from this result set is all the rows attributed to John on 2013-09-20. Generally what I'm looking for is a run of results from the same name, in a row, >= 3. I'm using Oracle 11, but I'm interested to know if this can be achieved with strict SQL, or if some kind of analytical function must be used.

Was it helpful?

Solution

You need multiple nested window functions:

SELECT *
FROM
 (
   SELECT the_date, name, grp,
      COUNT(*) OVER (PARTITION BY grp) AS cnt
   FROM
    (
      SELECT the_date, name, 
         SUM(flag) OVER (ORDER BY the_date) AS grp
      FROM
       (
         SELECT the_date, name, 
            CASE WHEN LAG(name) OVER (ORDER BY the_date) = name THEN 0 ELSE 1 END AS flag
         FROM orders
         WHERE 
             the_date BETWEEN 
                 TO_DATE('2013-09-18',..) AND 
                 TO_DATE('2013-09-22', ..)
       ) dt
    ) dt
 ) dt
WHERE cnt >= 3
ORDER BY the_date

OTHER TIPS

Try this

WITH ORDERS
    AS (SELECT
             TO_DATE ( '2013-09-18 00:00:01',
                     'YYYY-MM-DD HH24:MI:SS' )
                 AS THE_DATE,
             'John' AS NAME
        FROM
             DUAL
        UNION ALL
        SELECT
             TO_DATE ( '2013-09-19 00:00:01',
                     'YYYY-MM-DD HH24:MI:SS' )
                 AS THE_DATE,
             'James' AS NAME
        FROM
             DUAL
        UNION ALL
        SELECT
             TO_DATE ( '2013-09-20 00:00:01',
                     'YYYY-MM-DD HH24:MI:SS' )
                 AS THE_DATE,
             'John' AS NAME
        FROM
             DUAL
        UNION ALL
        SELECT
             TO_DATE ( '2013-09-20 00:00:02',
                     'YYYY-MM-DD HH24:MI:SS' )
                 AS THE_DATE,
             'John' AS NAME
        FROM
             DUAL
        UNION ALL
        SELECT
             TO_DATE ( '2013-09-20 00:00:03',
                     'YYYY-MM-DD HH24:MI:SS' )
                 AS THE_DATE,
             'John' AS NAME
        FROM
             DUAL
        UNION ALL
        SELECT
             TO_DATE ( '2013-09-20 00:00:04',
                     'YYYY-MM-DD HH24:MI:SS' )
                 AS THE_DATE,
             'John' AS NAME
        FROM
             DUAL
        UNION ALL
        SELECT
             TO_DATE ( '2013-09-21 16:00:01',
                     'YYYY-MM-DD HH24:MI:SS' )
                 AS THE_DATE,
             'Jennifer' AS NAME
        FROM
             DUAL)
SELECT
      B.*
FROM
      (SELECT
            TRUNC ( THE_DATE ) THE_DATE,
            NAME,
            COUNT ( * )
       FROM
            ORDERS
       WHERE
            THE_DATE BETWEEN TRUNC ( TO_DATE ( '2013-09-18',
                                        'YYYY-MM-DD' ) )
                       AND TRUNC ( TO_DATE ( '2013-09-22',
                                        'YYYY-MM-DD' ) )
       GROUP BY
            TRUNC ( THE_DATE ),
            NAME
       HAVING
            COUNT ( * ) >= 3) A,
      ORDERS B
WHERE
      A.NAME = B.NAME
      AND TRUNC ( A.THE_DATE ) = TRUNC ( B.THE_DATE );

OUTPUT

9/20/2013 12:00:01 AM   John
9/20/2013 12:00:02 AM   John
9/20/2013 12:00:03 AM   John
9/20/2013 12:00:04 AM   John
Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top