declare @consec_Numbers int = 6
;with cte as
(select a, 0 b from
#temp
union all
select t1.a, b + 1
from #temp t1 join cte c on c.a + 1 = t1.a
where c.a != t1.a
)
select distinct a - @consec_Numbers + 1 final from cte
where b + 1 >= @consec_Numbers
--
CREATE TABLE nbr
(
nbrs BIGINT
)
GO
INSERT INTO nbr VALUES
(9255551000),
(9255551010),
(9255551011),
(9255551012),
(9255551013),
(9255551014),
(9255551015),
(9255551020),
(9255551021),
(9255551022),
(9255551023),
(9255551024),
(9255551025)
GO
--
--
DECLARE @NoOfConsecutiveBlocks AS INT = 5
SELECT MIN(nbrs) StartBlockNbrs , MAX(nbrs) EndBlockNbrs
FROM
(
SELECT nbrs , rnk , COUNT(rnk) OVER (PARTITION BY rnk) cnt
FROM
(
SELECT * , nbrs - ROW_NUMBER() OVER (ORDER BY nbrs) rnk FROM nbr
)u
)k
WHERE cnt >= @NoOfConsecutiveBlocks
GROUP BY rnk
--
--
DECLARE @NoOfConsecutiveBlocks AS INT = 5
SELECT MIN(nbrs) StartBlockNbrs , MAX(nbrs) EndBlockNbrs
FROM
(
SELECT nbrs , rnk , COUNT(rnk) OVER (PARTITION BY rnk) cnt
FROM
(
SELECT * , nbrs - ROW_NUMBER() OVER (ORDER BY nbrs) rnk FROM nbr
)u
)k
WHERE cnt = @NoOfConsecutiveBlocks
GROUP BY rnk
--
--
DECLARE @NoOfConsecutiveBlocks AS INT = 5
SELECT MIN(nbrs) StartBlockNbrs , MAX(nbrs) EndBlockNbrs
FROM
(
SELECT nbrs , rnk , COUNT(rnk) OVER (PARTITION BY rnk) cnt
FROM
(
SELECT * , nbrs - ROW_NUMBER() OVER (ORDER BY nbrs) rnk FROM nbr
)u
)k
WHERE cnt >= @NoOfConsecutiveBlocks
GROUP BY rnk
--
DECLARE @NoOfConsecutiveBlocks AS INT = 1
SELECT MIN(PhoneNumber) StartBlockNbrs , MAX(PhoneNumber) EndBlockNbrs
FROM
(
SELECT PhoneNumber , rnk , COUNT(rnk) OVER (PARTITION BY rnk) cnt
FROM
(
SELECT * , PhoneNumber - ROW_NUMBER() OVER (ORDER BY PhoneNumber) rnk FROM [dbo].[tbl_NumberPool]
)u
)k
WHERE cnt >= @NoOfConsecutiveBlocks
GROUP BY rnk
DECLARE @NoOfConsecutiveBlocks AS INT = 5
SELECT MIN([PhoneNumber]) StartBlockNbrs , MAX([PhoneNumber]) EndBlockNbrs
FROM
(
SELECT [PhoneNumber] , rnk , COUNT(rnk) OVER (PARTITION BY rnk) cnt
FROM
(
SELECT * , [PhoneNumber] - ROW_NUMBER() OVER (ORDER BY [PhoneNumber]) rnk FROM [tbl_NumberPool]
)u
)k
WHERE cnt >= @NoOfConsecutiveBlocks
GROUP BY rnk
if object_id('tempdb..#Nbrs') is not null drop table #Nbrs
--
;with cte_Nums as (
select cast(2094902000 as bigint) as Num
union all
select Num + 1
from cte_Nums n
where n.Num <= 2094902999
)
--
select *
into #Nbrs
from cte_Nums n
option (maxrecursion 10000)
--
declare @BlockSize int = 5
--
;with cte_SetAnchors as (
select der.Num, der.Consecutive, der.PossibleAnchor,
der.PossibleAnchor + @BlockSize as EndOfRange
from (
select n.Num,
-- is this row consecutive with the one before?
case when n.Num - lag(n.Num) over(order by n.Num) = 1 then 1 else 0 end as Consecutive,
-- "anchor numbers" always start with a zero as our least signif (right most) digit
case when n.Num % 10 = 0 then Num else null end as PossibleAnchor
from #Nbrs n
) der
)
--
,cte_FindRanges as (
select a.*,
(select sum(Consecutive) from cte_SetAnchors a2
where a2.Num > a.PossibleAnchor
and a2.Num <= a.EndOfRange) as NbrConsecutive
from cte_SetAnchors a
)
select f.PossibleAnchor as Anchor,
f.EndOfRange, f.NbrConsecutive as ConsecutivePhoneNumbers
from cte_FindRanges f
where f.NbrConsecutive = @BlockSize
Anchor EndOfRange ConsecutivePhoneNumbers
2094902000 2094902005 5
2094902010 2094902015 5
2094902020 2094902025 5
2094902030 2094902035 5
2094902040 2094902045 5
2094902050 2094902055 5
2094902060 2094902065 5
...
Anchor EndOfRange ConsecutivePhoneNumbers
2094902000 2094902004 5
2094902005 2094902009 5
2094902010 2094902014 5
2094902000 2094902100 100
2094902010 2094902110 100
2094902020 2094902120 100
2094902030 2094902130 100
declare @consecs as int
set @consecs = 5
declare @Pnumbers table
([Pnumber] bigint, [Status] int)
;
INSERT INTO @Pnumbers
([Pnumber], [Status])
VALUES
(9255551000, 1),
(9255551010, 1),
(9255551011, 1),
(9255551012, 1),
(9255551013, 1),
(9255551014, 1),
(9255551015, 1),
(9255551020, 1),
(9255551021, 1),
(9255551022, 1),
(9255551023, 1),
(9255551024, 1),
(9255551025, 1)
And these 3 queries:
select
t.Pnumber AS starting_at
, t.Pnumber + ca.y AS ending_at
, ca.y AS Nums_available
, 'v1' as query
from @Pnumbers t
cross apply (
select count(*) y
from @Pnumbers x
where x.pnumber >= t.pnumber and x.pnumber <= (t.pnumber + @consecs)
and x.status = 1
) ca
where ca.y >= @consecs
order by t.Pnumber
select
t.Pnumber AS starting_at
, t.Pnumber + ca.y AS ending_at
, ca.y AS Nums_available
, 'v2' AS query
from @Pnumbers t
cross apply (
select count(*) y
from @Pnumbers x
where x.pnumber >= t.pnumber and x.pnumber <= (t.pnumber + @consecs)
and x.status = 1
) ca
where ca.y = @consecs
order by t.Pnumber
select
t.Pnumber AS starting_at
, t.Pnumber + ca.y AS ending_at
, ca.y AS Nums_available
, 'v3' AS query
from @Pnumbers t
cross apply (
select count(*) y
from @Pnumbers x
where x.pnumber <= t.pnumber and x.pnumber >= (t.pnumber - @consecs)
and x.status = 1
) ca
where ca.y = @consecs
order by t.Pnumber
I get these 3 different results:
+----+-------------+------------+----------------+-------+
| | starting_at | ending_at | Nums_available | query |
+----+-------------+------------+----------------+-------+
| 1 | 9255551010 | 9255551016 | 6 | v1 |
| 2 | 9255551011 | 9255551016 | 5 | v1 |
| 3 | 9255551020 | 9255551026 | 6 | v1 |
| 4 | 9255551021 | 9255551026 | 5 | v1 |
+----+-------------+------------+----------------+-------+
+----+-------------+------------+----------------+-------+
| | starting_at | ending_at | Nums_available | query |
+----+-------------+------------+----------------+-------+
| 1 | 9255551011 | 9255551016 | 5 | v2 |
| 2 | 9255551021 | 9255551026 | 5 | v2 |
+----+-------------+------------+----------------+-------+
+----+-------------+------------+----------------+-------+
| | starting_at | ending_at | Nums_available | query |
+----+-------------+------------+----------------+-------+
| 1 | 9255551014 | 9255551019 | 5 | v3 |
| 2 | 9255551024 | 9255551029 | 5 | v3 |
+----+-------------+------------+----------------+-------+
The sample data is derived from original question and subsequent comments, and the result output is assumed.select
t.Pnumber AS starting_at
, case when ca.y >= @consecs then t.Pnumber + @consecs end AS ending_at
, ca.y AS Nums_available
, 'v4' as query
from @Pnumbers t
cross apply (
select count(*) y
from @Pnumbers x
where x.pnumber >= t.pnumber and x.pnumber <= (t.pnumber + @consecs)
and x.status = 1
) ca
where ca.y >= @consecs
order by t.Pnumber
+----+-------------+------------+----------------+-------+
| | starting_at | ending_at | Nums_available | query |
+----+-------------+------------+----------------+-------+
| 1 | 9255551010 | 9255551015 | 6 | v4 |
| 2 | 9255551011 | 9255551016 | 5 | v4 |
| 3 | 9255551020 | 9255551025 | 6 | v4 |
| 4 | 9255551021 | 9255551026 | 5 | v4 |
+----+-------------+------------+----------------+-------+
DECLARE @consecs AS INT = 5
select
t.PhoneNumber AS starting_at
, t.PhoneNumber + ca.y AS ending_at
, ca.y AS Nums_available
, 'v1' as query
from tbl_NumberPool t
cross apply (
select count(*) y
from tbl_NumberPool x
where x.PhoneNumber >= t.PhoneNumber and x.PhoneNumber <= (t.PhoneNumber + @consecs)
and x.status = 1
) ca
where ca.y >= @consecs
order by t.PhoneNumber
starting_at ending_at Nums_available query
2094902000 2094902006 6 v1
2094902001 2094902007 6 v1
2094902002 2094902008 6 v1
2094902003 2094902009 6 v1
2094902004 2094902010 6 v1
2094902005 2094902011 6 v1
2094902006 2094902012 6 v1
2094902007 2094902013 6 v1
2094902008 2094902014 6 v1
DECLARE @consecs AS INT = 100
select
t.PhoneNumber AS starting_at
, t.PhoneNumber + ca.y AS ending_at
, ca.y AS Nums_available
, 'v2' AS query
from tbl_NumberPool t
cross apply (
select count(*) y
from tbl_NumberPool x
where x.PhoneNumber >= t.PhoneNumber and x.PhoneNumber <= (t.PhoneNumber + @consecs)
and x.status = 1
) ca
where ca.y = @consecs
order by t.PhoneNumber
starting_at ending_at Nums_available query
2094902900 2094903000 100 v2
/**-----------------------------------------------------------------------------------------------------**/
/**-----------------------------------------------------------------------------------------------------**/
if object_id('tempdb..#PossibleBlocks') is not null drop table #PossibleBlocks
if object_id('tempdb..#Final') is not null drop table #Final
--
declare @BlockSize int = 8
-- identify our consecutive numbers using LAG()
;with cte_ConsecutiveNums as (
select n.Num,
-- is this row consecutive with the one before?
case when n.Num - lag(n.Num) over(order by n.Num) = 1 then 1 else 0 end as Consecutive,
row_number() over(order by n.Num) as [Row]
from #Nbrs n
)
-- determine which numbers can be "anchors" (the start of a block of numbers)
,cte_FindAnchors as (
select cn.Num, cn.Consecutive, cn.[Row],
case when (select sum(cn2.Consecutive) from cte_ConsecutiveNums cn2
where cn2.[Row] between cn.[Row] + 1 and cn.[Row] + (@BlockSize - 1)) = (@BlockSize - 1)
then 1
end as EnoughNumsForGroup
from cte_ConsecutiveNums cn
)
-- select both the beginning and end phone number values for all possible blocks
,cte_FindEndOfRange as (
select f.Num, f.Consecutive, f.[Row], f.EnoughNumsForGroup,
case when f.EnoughNumsForGroup = 1 then f.Num + (@BlockSize - 1) end as EndOfRange
from cte_FindAnchors f
)
select *
into #PossibleBlocks
from cte_FindEndOfRange f
-- we don't want overlapping blocks, so we'll identify "next anchor" values
select f.Num, f.Consecutive, f.EnoughNumsForGroup, f.EndOfRange,
(select min(f2.Num) from #PossibleBlocks f2 where f2.Num > f.EndOfRange
and f2.EndOfRange is not null) as NextAnchor
into #Final
from #PossibleBlocks f
-- recurse through our set to return all valid blocks
;with cte_Recurse as (
select f.*
from #Final as f
where f.Num = (select min(f2.Num) from #Final as f2 where f2.EnoughNumsForGroup = 1)
union all
select f.*
from #Final as f
join cte_Recurse r
on r.NextAnchor = f.Num
)
select r.Num, r.EndOfRange, (r.EndOfRange - r.Num) + 1 PhoneNumbers
from cte_Recurse r
option (maxrecursion 10000)
/**-----------------------------------------------------------------------------------------------------**/
/**-----------------------------------------------------------------------------------------------------**/
if object_id('tempdb..#PossibleBlocks') is not null drop table #PossibleBlocks
if object_id('tempdb..#Final') is not null drop table #Final
--
declare @BlockSize int = 8
-- identify our consecutive numbers using LAG()
;with cte_ConsecutiveNums as (
select n.Num,
-- is this row consecutive with the one before?
case when n.Num - lag(n.Num) over(order by n.Num) = 1 then 1 else 0 end as Consecutive,
row_number() over(order by n.Num) as [Row]
from #Nbrs n
)
-- determine which numbers can be "anchors" (the start of a block of numbers)
,cte_FindAnchors as (
select cn.Num, cn.Consecutive, cn.[Row],
case when (select sum(cn2.Consecutive) from cte_ConsecutiveNums cn2
where cn2.[Row] between cn.[Row] + 1 and cn.[Row] + (@BlockSize - 1)) = (@BlockSize - 1)
then 1
end as EnoughNumsForGroup
from cte_ConsecutiveNums cn
)
-- select both the beginning and end phone number values for all possible blocks
,cte_FindEndOfRange as (
select f.Num, f.Consecutive, f.[Row], f.EnoughNumsForGroup,
case when f.EnoughNumsForGroup = 1 then f.Num + (@BlockSize - 1) end as EndOfRange
from cte_FindAnchors f
)
select *
into #PossibleBlocks
from cte_FindEndOfRange f
-- we don't want overlapping blocks, so we'll identify "next anchor" values
select f.Num, f.Consecutive, f.EnoughNumsForGroup, f.EndOfRange,
(select min(f2.Num) from #PossibleBlocks f2 where f2.Num > f.EndOfRange
and f2.EndOfRange is not null) as NextAnchor
into #Final
from #PossibleBlocks f
-- recurse through our set to return all valid blocks
;with cte_Recurse as (
select f.*
from #Final as f
where f.Num = (select min(f2.Num) from #Final as f2 where f2.EnoughNumsForGroup = 1)
union all
select f.*
from #Final as f
join cte_Recurse r
on r.NextAnchor = f.Num
)
select r.Num, r.EndOfRange, (r.EndOfRange - r.Num) + 1 PhoneNumbers
from cte_Recurse r
option (maxrecursion 10000)