I have a list of number ranges and need to convert them to a list of all numbers in these ranges. I am using an MS SQL database
I have a table with the bellow information
Range Start | Range End |
---|---|
01135489651 | 01135489750 |
01142225487 | 01142225686 |
01159857992 | 01159858090 |
I would like a SQL method to expand the ranges to individual numbers, one per row like below.
Result |
---|
01135489651 |
01135489652 |
... |
... |
01135489749 |
01135489750 |
01142225487 |
01142225488 |
... |
... |
01142225685 |
01142225686 |
01159857992 |
01159857993 |
... |
... |
01159858089 |
01159858090 |
Ideally as a CTE without the need for temp tables.
Does anyone have a working solution?
CodePudding user response:
Simple recursive cte version. Let the cte generate all numbers from smallest RangeStart to largest RangeEnd. JOIN:
WITH RECURSIVE cte(n) as
(
select min(RangeStart) from tbl
UNION ALL
SELECT n 1
FROM cte
WHERE n <= (select max(RangeEnd) from tbl)
)
select n
from cte
join tbl on n between RangeStart and RangeEnd
If your columns are character instead of numeric, add some cast's:
WITH RECURSIVE cte(n) as
(
select min(cast(RangeStart as bigint)) from tbl
UNION ALL
SELECT n 1
FROM cte
WHERE n <= (select max(cast(RangeEnd as bigint)) from tbl)
)
select '0' || cast(n as varchar(15))
from cte
join tbl on n between cast(RangeStart as bigint)
and cast(RangeEnd as bigint)
CodePudding user response:
Without the Vertica TIMESERIES
clause (PostGreSQL can also generate a series out of nothing, but differently) , try this:
WITH
-- input ..
indata(Range_Start,Range_End) AS (
SELECT '01135489651','01135489750'
UNION ALL SELECT '01142225487','01142225686'
UNION ALL SELECT '01159857992','01159858090'
)
-- REAL query starts here, replace following comma with "WITH"
,
-- max range size is just under 200, so need a list of 200 consecutive integers ..
-- create a table "units" with integers 0 through 9 ...
units(unit) AS (
SELECT 0
UNION ALL SELECT 1
UNION ALL SELECT 2
UNION ALL SELECT 3
UNION ALL SELECT 4
UNION ALL SELECT 5
UNION ALL SELECT 6
UNION ALL SELECT 7
UNION ALL SELECT 8
UNION ALL SELECT 9
)
,
-- cross join integers 0 through 9 with each other three times and limit the
-- list for the hundreds to 0 and 1, leaving you with 0 through 199 ....
i(i) AS (
SELECT
h.unit * 100 d.unit * 10 u.unit
FROM units h
CROSS JOIN units d
CROSS JOIN units u
WHERE h.unit < 2
)
SELECT
'0'
||CAST (
CAST(range_start AS INTEGER) i
AS VARCHAR(16)
) AS result
FROM indata
CROSS JOIN i
WHERE CAST(range_start AS INTEGER) i <= CAST(range_end AS INTEGER)
ORDER BY result
;
CodePudding user response:
as you don't have more then 200 numbers to compute, only one simple select query can be used with values and cross apply :
select
[Range Start]
,[Range End]
,[n] = n1 n10 n100
,[number] = [Range Start] n1 n10 n100
from (values(01135489651,01135489750),(01142225487,01142225686),(01159857992,01159858090))ranges([Range Start],[Range End])
CROSS APPLY (values(0),(1),(2),(3),(4),(5),(6),(7),(8),(9)) n1(n1)
CROSS APPLY (values(0),(10),(20),(30),(40),(50),(60),(70),(80), (90))n10(n10)
CROSS APPLY (values(0),(100))n100(n100)
where
n1 n10 n100 BETWEEN 0 and [Range End] - [Range Start]
Range Start | Range End | n | number |
---|---|---|---|
1135489651 | 1135489750 | 0 | 1135489651 |
1135489651 | 1135489750 | 1 | 1135489652 |
... | |||
1135489651 | 1135489750 | 99 | 1135489750 |
1142225487 | 1142225686 | 0 | 1142225487 |
1142225487 | 1142225686 | 1 | 1142225488 |
... | |||
1142225487 | 1142225686 | 198 | 1142225685 |
1142225487 | 1142225686 | 199 | 1142225686 |
CodePudding user response:
you can create a table in your database with following syntax that provide you with a very large values
SELECT TOP 1000000000000
ROW_NUMBER() OVER(PARTITION BY 1 ORDER BY A.name) AS 'Range'
into numbers --- a number table with list of values
FROM syscolumns A, syscolumns B
after that use the following to create table in your database
SELECT * INTO your_new_table
from numbers
where range between 01135489651 and 01135489750
union
select range
from numbers
where range between 01142225487 and 01142225686
union
select range
from numbers
where range between 01159857992 and 01159858090