Warm tip: This article is reproduced from stackoverflow.com, please click
count grouping oracle sql

Calculate count based on multiple groups of 7 number range in Oracle

发布于 2020-04-03 23:50:55

Can someone please help me out, I stuck here.

Given

AMOUNT  CUSTOMER_NUMBER GROUPID SEQF
1000+   5555            51      2       
1000+   5555            52      3
1000+   5555            55      4   
1000+   5555            56      4   
1000+   5555            57      4       
1000+   5555            58      2   
1000+   5555            59      4   
1000+   5555            61      2
2000+   6666            55      2
.
.   
.
.

By considering AMOUNT and CUSTOMER_NUMBER columns, here creating group within 7 GROUPID Numbers

For e.g. 1st Group for 5555 CUSTOMER_NUMBER -> (51 to 57 GROUP ID), 2nd Group for 5555 CUSTOMER_NUMBER (58 to 61 GROUP ID), 3rd Group for 6666 CUSTOMER_NUMBER (55 GROUP ID)

Needed:

IF SEQF >=2 in 1st Group in any of the GROUPID from 51 to 57 then consider COUNT(SEQF) = 1

IF SEQF >=2 in 2nd Group in any of the GROUPID from 58 to 61 then consider COUNT(SEQF) = 1

so total here

AMOUNT  CUSTOMER_NUMBER COUNT(SEQF)
1000+       5555                2

IF SEQF >=2 in 3rd Group in any of the GROUPID from 55 then consider COUNT(SEQF) = 1

AMOUNT  CUSTOMER_NUMBER COUNT(SEQF)
2000+       6666                1

Desired Output

AMOUNT  CUSTOMER_NUMBER COUNT(SEQF)
1000+       5555                2
2000+       6666                1
Questioner
NewTechGuy
Viewed
44
MT0 2020-01-31 21:20

None of the other answers solve the problem where there are gaps between groups (they just assume groups are contiguous). This will skip gaps and put the groupid into ranges of 7.

Oracle Setup:

create table data(amount, customer_number, groupid, seqf) as (
    select '1000+', 5555, 51, 2 from dual union all
    select '1000+', 5555, 52, 3 from dual union all
    select '1000+', 5555, 55, 4 from dual union all
    select '1000+', 5555, 56, 4 from dual union all
    select '1000+', 5555, 57, 4 from dual union all
    select '1000+', 5555, 60, 2 from dual union all
    select '1000+', 5555, 61, 4 from dual union all
    select '1000+', 5555, 65, 2 from dual union all
    select '1000+', 5555, 69, 2 from dual union all
    select '2000+', 6666, 55, 2 from dual );

Query 1:

This finds the groups:

SELECT amount,
       customer_number,
       groupid,
       groupid + 6 AS max_groupid
FROM   (
  SELECT d.*,
         MIN( groupid )
           OVER ( PARTITION BY amount, customer_number )
           AS min_groupid,
         MIN( groupid )
           OVER (
             PARTITION BY amount, customer_number
             ORDER BY groupid
             RANGE BETWEEN 7 FOLLOWING AND UNBOUNDED FOLLOWING
           )
           AS next_groupid
  FROM   data d
)
START WITH groupid = min_groupid
CONNECT BY PRIOR amount          = amount
AND        PRIOR customer_number = customer_number
AND        PRIOR next_groupid    = groupid

which outputs:

AMOUNT | CUSTOMER_NUMBER | GROUPID | MAX_GROUPID
:----- | --------------: | ------: | ----------:
1000+  |            5555 |      51 |          57
1000+  |            5555 |      60 |          66
1000+  |            5555 |      69 |          75
2000+  |            6666 |      55 |          61

Query 2:

This counts the groups:

SELECT amount,
       customer_number,
       COUNT(*)
FROM   (
  SELECT d.*,
         MIN( groupid )
           OVER ( PARTITION BY amount, customer_number )
           AS min_groupid,
         MIN( groupid )
           OVER (
             PARTITION BY amount, customer_number
             ORDER BY groupid
             RANGE BETWEEN 7 FOLLOWING AND UNBOUNDED FOLLOWING
           )
           AS next_groupid
  FROM   data d
)
START WITH groupid = min_groupid
CONNECT BY PRIOR amount          = amount
AND        PRIOR customer_number = customer_number
AND        PRIOR next_groupid    = groupid
GROUP BY amount, customer_number

which outputs:

AMOUNT | CUSTOMER_NUMBER | COUNT(*)
:----- | --------------: | -------:
1000+  |            5555 |        3
2000+  |            6666 |        1

db<>fiddle here