如何在[sql server]的列中以逗号分隔[number - (to)number]中的所有单个数字

时间:2017-06-08 06:48:06

标签: sql-server

sqlserver中的数据列就像     的数     1000-1050,1054,1090-1230,1245

numbers
-------
1000-1050, 1054, 1090-1230, 1245

如何获得如下风格:

numbers
-------
1000
1001
1002
1003
1004
...
1050
1054
1090
1091
1092
...
1245

3 个答案:

答案 0 :(得分:0)

您可以使用拆分功能和APPLY这样的

DECLARE @SampleData AS TABLE
(
    numbers varchar(200)
)

INSERT INTO @SampleData
VALUES ('1000-1050, 1054, 1090-1230, 1245')

;WITH temp AS
(
    SELECT 1 AS Number
    UNION ALL
    SELECT t.Number + 1 FROM temp t
    WHERE t.Number < 5000
) -- return table from 1 --> 5000
SELECT  DISTINCT
       ca2.*
FROM @SampleData sd
CROSS APPLY 
(
    SELECT pos, LTRIM(Value) AS Value 
    FROM dbo.SplitString(sd.Numbers,',')
) ca1
CROSS APPLY
(
    SELECT * 
    FROM temp t WHERE t.Number  BETWEEN LEFT(ca1.[Value], charindex('-', ca1.[Value] + '-') - 1) AND
                          CASE
                             WHEN len(ca1.[Value]) < charindex('-', ca1.[Value] + '-') THEN ca1.[Value]
                             ELSE RIGHT(ca1.[Value], len(ca1.[Value]) - charindex('-', ca1.[Value] + '-'))
                          END
) ca2
OPTION (MAXRECURSION 0)

分割功能

CREATE FUNCTION [dbo].[SplitString] (@Text varchar(max),@Delimiter varchar(10))
Returns Table 
As
Return (  
   Select Pos = Row_Number() over (Order By (Select null))
        ,Value = LTrim(RTrim(B.i.value('(./text())[1]', 'varchar(max)')))
   From (Select x = Cast('<x>'+ Replace(@Text,@Delimiter,'</x><x>')+'</x>' as xml).query('.')) as A 
   Cross Apply x.nodes('x') AS B(i)
);

演示链接:http://rextester.com/GIPGR78132

答案 1 :(得分:0)

首先拆分逗号分隔值,然后使用递归公用表表达式获取值。

Declare @values nvarchar(max) = '1000-1050, 1054, 1090-1230, 1245'

;with ranges_cte as
(
    select cast(case pos when 0 then  ResultValue else left(ResultValue,pos-1) end as int) first, cast(case pos when 0 then  ResultValue else substring(ResultValue,pos+1,len(ResultValue)-pos) end as int) Last
    from (
    select ResultValue, charINDEx('-',ResultValue) pos 
    from dbo.SplitString(@values,',')) x
)
, values_rte as
(
select first,last,first as active
from ranges_cte
union all
select first,last,active +1 as active
from values_rte
where active< last
)

select * 
from values_rte 
OPTION (MAXRECURSION 0)

分割值的功能:

Create FUNCTION [dbo].[SplitString] (@StringArray NVARCHAR(MAX), @Delimiter NVARCHAR(10)) 
RETURNS @ResultedValues table 
(
nr int,
ResultValue nvarchar(max)
) 
AS 
--select * from dbo.splitstring ('123,456,789',',')
BEGIN
  declare @string nvarchar(max)
  declare @nr int = 1
  set @string = @StringArray
  WHILE (CHARINDEX(@Delimiter,@String)>0)
   BEGIN 
    INSERT INTO @ResultedValues (nr,ResultValue) VALUES (@nr,LTRIM(RTRIM(SUBSTRING(@String,1,CHARINDEX(@Delimiter,@String)-1))))
    SET @String = SUBSTRING(@String,   CHARINDEX(@Delimiter,@String)+LEN(@Delimiter),LEN(@String))
    set @nr = @nr +1
   END 
INSERT INTO @ResultedValues (nr,ResultValue ) VALUES ( @nr, LTRIM(RTRIM(@String)))
RETURN
END

答案 2 :(得分:0)

创建拆分功能:

CREATE FUNCTION [dbo].[SplitIDsTest]
(
    @idList varchar(4000)
)
RETURNS @parsedList TABLE
(
    Id varchar(50),
    Nr int
)
AS
BEGIN

    DECLARE @id varchar(10), @pos int
    DECLARE @nr int = 0;

    SET @idList = LTRIM(RTRIM(@idList)) + ','
    SET @Pos = CHARINDEX(',', @idList)       

    IF REPLACE(@idList, ',', '') <> ''
        BEGIN
            WHILE @Pos > 0   
                BEGIN
                    SET @id = LTRIM(RTRIM(LEFT(@idList, @pos - 1)))

                    IF @id <> '' 
                    BEGIN
                        set @nr += 1;
                        INSERT INTO @ParsedList (Id, Nr)
                        VALUES (@id, @nr);
                    END

                    SET @idList = RIGHT(@idList, LEN(@idList) - @pos) -- 'WMPC,' (inklusive Komma) links vom Eingabeparameter abschneiden, weil jetzt der nächste Wert gesucht wird
                    SET @pos = CHARINDEX(',', @idList, 1)             -- Nächste Position eines Kommas suchen und in der WHILE-Schleife weitermachen
                END
        END  

    RETURN
END

然后是一个计数表:

select top 1000000 N=identity(int, 1, 1)
  into dbo.Tally
  from master.dbo.syscolumns a cross join master.dbo.syscolumns b;

然后使用:

select distinct Tally.N
  from SplitIDsTest('10-12, 34, 9') splitted
  join Tally on 1 = case
                     when CHARINDEX('-', splitted.Id) > 0 then
                      case
                       when Tally.N between cast(left(splitted.Id, CHARINDEX('-', splitted.Id) - 1) as int)
                                        and cast(right(splitted.Id, len(splitted.Id) - CHARINDEX('-', splitted.Id)) as int) then 1
                       else 0
                      end
                     when Tally.N = cast(splitted.Id as int) then 1
                     else 0
                    end
 order by Tally.N