Tek-Tips is the largest IT community on the Internet today!

Members share and learn making Tek-Tips Forums the best source of peer-reviewed technical information on the Internet!

  • Congratulations Mike Lewis on being selected by the Tek-Tips community for having the most helpful posts in the forums last week. Way to Go!

Convert Comma Separated List of INTs to a Range 2

Status
Not open for further replies.

rharsh

Technical User
Apr 2, 2004
960
US
I have a series of string values that are generally a contiguous list of integers in a format of "1,2,3,4,5," -- although sometimes there can be contiguous ranges mixed with non-contiguous entries, such as "0,1,2,3,10,13,20,21,22,".

What I'm hoping to do is convert them to a range notation. So
Code:
"1,2,3,4,5," becomes "1-5" and
"0,1,2,3,10,13,20,21,22," becomes "0-3,10,13,20-22"

I've implemented fixes in both perl and Crystal Reports formulas. Googling hasn't seemed to produce much help, but maybe I'm searching for the wrong thing. I was hoping someone might be able to point me in the right direction so I could implement this with a user defined function. Thanks!
 
Are you trying to take the existing list and convert it to range form, or are you trying to take a list that includes ranges and use it in some way?

Tamar
 
Thank you for the response, the field has values that are a list, some examples would be:
Code:
'1,'
'1,2,3,4,5,'
'1,2,3,5,6,10,'
And I'd like to convert it to a range (or ranges) if possible. Using those examples, something like:
Code:
'1'
'1-5'
'1-3,5-6,10'
I've continued searching and it seems the reverse is fairly easy (from a range to a list) but I'm not even sure where to start with identifying the ranges and recursing through the elements in the list.
 
yeah... searching for the right thing is most often where it fails.

This is a classic Gap and Islands case.

Code below is based on Jeff Moden's example at you will also need the split function found at or the enhanced version if your sql version allows the LEAD() function at
Below two blocks of code - first one just to show how it works, the second one would be the one you would stick on a function to return the string as you asked for.
It is advisable that you do the function as an ITVF for performance reasons

Code:
declare @Input varchar(200) = '0,1,2,3,10,13,20,21,22,';

with sequences
as
(select convert(int, t.Item) as SeqNo
       from dbo.DelimitedSplit8K(@Input, ',') t
       where t.Item <> ''
),
groupedseqno
as
( -- Find the unique sequences and assign them to a group.
   -- adjacent Sequences will be a part of the same group.
   select UniqueSeqNo = SeqNo
        , SequenceGroup = SeqNo - row_number() over (order by SeqNo)
       from sequences
       group by SeqNo
)
-- Now, if we find the MIN and MAX sequence for each Group, we'll have the
-- Start and End sequence of each group of contiguous sequence.  While we're at it,
-- we can also figure out how many sequences are in each range of sequences.
select SequenceGroup
     , startseqno = min(UniqueSeqNo)
     , endseqno = max(UniqueSeqNo)
     , rangeentries = max(UniqueSeqNo) - min(UniqueSeqNo) + 1
from groupedseqno
group by SequenceGroup
order by startseqno;

--output
SequenceGroup startseqno endseqno rangeentries
-1            0          3        4
5             10         10       1
7             13         13       1
13            20         22       3

Code:
declare @Input varchar(200) = '0,1,2,3,10,13,20,21,22,';
with sequences
as
(select convert(int, t.Item) as SeqNo
       from dbo.DelimitedSplit8K(@Input, ',') t
       where t.Item <> ''
),
groupedseqno
as
( -- Find the unique sequences and assign them to a group.
   -- adjacent Sequences will be a part of the same group.
   select UniqueSeqNo = SeqNo
        , SequenceGroup = SeqNo - row_number() over (order by SeqNo)
       from sequences
       group by SeqNo
)
-- Now, if we find the MIN and MAX sequence for each Group, we'll have the
-- Start and End sequence of each group of contiguous sequence.  While we're at it,
-- we can also figure out how many sequences are in each range of sequences.
select stuff(
           (select ',' +
                        case
                        when min(UniqueSeqNo) = max(UniqueSeqNo)
                            then convert(varchar(10), max(UniqueSeqNo))
                        else convert(varchar(10), min(UniqueSeqNo)) + '-' + convert(varchar(10), max(UniqueSeqNo))
                        end

                  from groupedseqno
                  group by SequenceGroup
                  for xml path ('')
           ), 1, 1, ''
            ); 
-- output
0-3,10,13,20-22

Regards

Frederico Fonseca
SysSoft Integrated Ltd

FAQ219-2884
FAQ181-2886
 
Wow, thank you! Lots to read through there. Thank you for the links and the sample code!
 
Status
Not open for further replies.

Part and Inventory Search

Sponsor

Back
Top