2011-02-07 76 views
1

如何在SQL Server中返回字符串中第n个元素的索引。比如我有字符串:A,B,C,d,E 现在我想收到的所有元素,第三昏迷之前,所以A,B,C。为了做到这一点,我需要有第三次昏迷指数。 Charindex不适合在这里,因为我不能通过昏迷的数量,为此我想索引。有没有可以做到的内置函数?使用tsql返回字符串中第n个元素的索引

更新,@Andriy M.

嘿,链接你指出我也很有用。下面,我已经修改了显示SQL一点得到我想要的东西:

CREATE FUNCTION [dbo].[nthindexsub](@String varchar(8000), @Delimiter char(1), @DelimitersCount int)  
returns varchar(8000) 
as  
begin  
    declare @Substring varchar(8000) 
    declare @temptable TABLE (itemindex int identity(1,1), items varchar(8000)) 
    declare @idx int  
    declare @slice varchar(8000)  

    select @idx = 1  
     if len(@String)<1 or @String is null return @Substring 

    while @idx!= 0  
    begin  
     set @idx = charindex(@Delimiter,@String)  
     if @idx!=0  
      set @slice = left(@String,@idx - 1)  
     else  
      set @slice = @String  

     if(len(@slice)>0) 
      insert into @temptable(Items) values(@slice)  

     set @String = right(@String,len(@String) - @idx)  
     if len(@String) = 0 break  
    end 

    select @Substring = COALESCE(@Substring + ',', '') + items from @temptable where itemindex <= @DelimitersCount 
    return @Substring; 
end 

用法:

select dbo.nthindexsub('a,b,c,d,e', ',', 3) 

结果是:A,B,C

+0

类似的问题已经解决了这里:http://stackoverflow.com/问题/ 4911153 /按索引获取特定部分的字符串 – 2011-02-07 13:52:22

回答

2

我不知道你为什么只是想索引?为什么不把它们拆分成行,使用行更快更好。下面是一个简单的TSQL分裂例如:

DECLARE @List varchar(500) 
     ,@SplitOn char(1) 
SELECT @List='aaa,bb,c,dd,eeee' 
     ,@SplitOn=',' 
;WITH NumbersCTE AS 
(
    SELECT 1 AS Number 
    UNION ALL 
    SELECT Number+1 
     FROM NumbersCTE 
     WHERE Number<LEN(@List) 
) 
, AllSplit AS 
(
    SELECT 
     ROW_NUMBER() OVER(ORDER BY number) AS RowNumber 
      ,LTRIM(RTRIM(SUBSTRING(ListValue, number+1, CHARINDEX(@SplitOn, ListValue, number+1)-number - 1))) AS ListValue 
     FROM (
       SELECT @SplitOn + @List + @SplitOn AS ListValue 
      ) AS InnerQuery 
      INNER JOIN NumbersCTE n ON n.Number < LEN(InnerQuery.ListValue) 
     WHERE SUBSTRING(ListValue, number, 1) = @SplitOn 
) 
SELECT 
    ListValue 
    FROM AllSplit 
    WHERE RowNumber<=3 

输出

ListValue 
---------------- 
aaa 
bb 
c 

有很多方法SQL Server中的字符串分割2005年本文介绍了几乎所有的方法的优点和缺点:

"Arrays and Lists in SQL Server 2005 and Beyond, When Table Value Parameters Do Not Cut it" by Erland Sommarskog

您需要创建一个拆分功能。这是一个分裂的功能如何使用:

SELECT 
    * 
    FROM YourTable        y 
    INNER JOIN dbo.yourSplitFunction(@Parameter) s ON y.ID=s.Value 

I prefer the number table approach to split a string in TSQL但也有许多方法来拆分在SQL Server中的字符串(前面的例子中,我使用的CTE),见前面的链接,这也解释了正反各自的CONs。

对于数字表的方法来工作,你需要做的这一次表的设置,这将创建一个包含从1到10000行的表Numbers

SELECT TOP 10000 IDENTITY(int,1,1) AS Number 
    INTO Numbers 
    FROM sys.objects s1 
    CROSS JOIN sys.objects s2 
ALTER TABLE Numbers ADD CONSTRAINT PK_Numbers PRIMARY KEY CLUSTERED (Number) 

一旦Numbers表格设置,创建此分割功能:

CREATE FUNCTION [dbo].[FN_ListToTable] 
(
    @SplitOn char(1)  --REQUIRED, the character to split the @List string on 
    ,@List  varchar(8000)--REQUIRED, the list to split apart 
) 
RETURNS TABLE 
AS 
RETURN 
(

    ---------------- 
    --SINGLE QUERY-- --this will not return empty rows 
    ---------------- 
    SELECT 
     ListValue 
     FROM (SELECT 
        LTRIM(RTRIM(SUBSTRING(List2, number+1, CHARINDEX(@SplitOn, List2, number+1)-number - 1))) AS ListValue 
        FROM (
          SELECT @SplitOn + @List + @SplitOn AS List2 
         ) AS dt 
         INNER JOIN Numbers n ON n.Number < LEN(dt.List2) 
        WHERE SUBSTRING(List2, number, 1) = @SplitOn 
      ) dt2 
     WHERE ListValue IS NOT NULL AND ListValue!='' 

); 
GO 

您现在可以轻松地拆分CSV字符串转换成表格,并加入就可以了:

select * from dbo.FN_ListToTable(',','1,2,3,,,4,5,6777,,,') 

OUTPUT:

ListValue 
----------------------- 
1 
2 
3 
4 
5 
6777 

(6 row(s) affected) 

您可以使用CSV字符串这样,没必要临时表:

SELECT 
    y.* 
    FROM YourTable y 
     INNER JOIN dbo.FN_ListToTable(',',@MyList) x ON y.pk=x.ListValue 
    Where y.aaa='5' 
1

有可能在TSQL中做,但是 TSQL不擅长(或设计)字符串操作,因此如果经常调用它可能会很慢。

可能会更好地创建一个CLR Stored Procedure

0
如果你想

只想前三个元素,尝试嵌套CHARINDEX这样的:

DECLARE @YourTable table (csv varchar(50)) 
INSERT @YourTable VALUES ('aaa,bb,c,dd,eeee') 
INSERT @YourTable VALUES ('aaa,bb,c,dd') 
INSERT @YourTable VALUES ('aaa,bb,c') 
INSERT @YourTable VALUES ('aaa,bb') 
INSERT @YourTable VALUES ('aaa') 
INSERT @YourTable VALUES (null) 

SELECT 
    csv 
     ,CHARINDEX(',',csv+',',CHARINDEX(',',csv+',',CHARINDEX(',',csv+',',0)+1)+1) AS ThirdComma 
    FROM @YourTable 
    WHERE CHARINDEX(',',csv,0)>0 
     AND CHARINDEX(',',csv+',',CHARINDEX(',',csv+',',CHARINDEX(',',csv+',',0)+1)+1)>0 

OUTPUT:

csv             
-------------------------------------------------- ----------- 
aaa,bb,c,dd,eeee         9 
aaa,bb,c,dd          9 
aaa,bb,c           9 

这将只返回有三个元素的行。如果你想它的时候有一,二,和/或三个,试试这个:

DECLARE @YourTable table (csv varchar(50)) 
INSERT @YourTable VALUES ('aaa,bb,c,dd,eeee') 
INSERT @YourTable VALUES ('aaa,bb,c,dd') 
INSERT @YourTable VALUES ('aaa,bb,c') 
INSERT @YourTable VALUES ('aaa,bb') 
INSERT @YourTable VALUES ('aaa') 
INSERT @YourTable VALUES (null) 

;WITH FindThird AS 
(
    SELECT csv, CHARINDEX(',',csv+',',CHARINDEX(',',csv+',',CHARINDEX(',',csv+',',0)+1)+1) AS ThirdComma 
    FROM @YourTable 
) 
SELECT 
    csv 
     ,CASE 
      WHEN ThirdComma IS NULL OR ThirdComma=0 THEN LEN(csv)+1 
      ELSE ThirdComma 
     END AS ThirdComma 
    FROM FindThird 

OUTPUT:

csv     ThirdComma 
------------------- ----------- 
aaa,bb,c,dd,eeee 9 
aaa,bb,c,dd   9 
aaa,bb,c   9 
aaa,bb    7 
aaa     4 
NULL    NULL