在RIGHT()或SUBSTRING()中使用CHARINDEX()拆分字符串会返回不正确的结果

时间:2017-11-02 12:48:54

标签: sql-server charindex

我想将一个列拆分为两个。我想从单元格值'('中选择值,所以这是我的要求: 输入字符串:

col: mystr
----------
123(0)
233 (123)
23 (A)
2 (122)

必需输出:

Output
-------
(0)
(123)
(A)
(122)

我做了以下事情:

 SELECT right(mystr,LEN(mystr)-
 CASE WHEN CHARINDEX('(',mystr)=0 THEN LEN(mystr) 
 ELSE CHARINDEX('(',mystr) END 
 + 1) 
 FROM docs

工作原理:我想先选择我找到的索引'(',然后选择旁边的值。由CHARINDEX()从左到右工作。所以而不是:

select right(mystr,CHARINDEX('(',mystr))

我从总长度LEN(mystr)-CHARINDEX('(',mystr)中减去了索引。

在这里,我发现了一个未找到'('并且'CHARINDEX()'返回0}的情况。因此,如果找不到'(',我会创建整个术语0由:

CASE WHEN CHARINDEX('(',mystr)=0 THEN LEN(mystr) 
ELSE CHARINDEX('(',mystr) END

此处未选择第一个元素,因此我将+1添加到整个术语中,但会产生额外的值:

mystr Out without +1,  Out with +1, Out with +1 moved inside else;  desired 
-----   ------------   -----------    -----------------             -------
 112        ''             2              ''                          ''
 1(0)       0)             (0)             )                          (0)
 1 (12)     12)            (12)            )                          (12)

我也试过了substring(),但它有同样的问题:

SELECT substring(mystr,
CASE WHEN CHARINDEX('(',mystr)=0 THEN LEN(mystr) 
ELSE CHARINDEX('(',mystr) END,
LEN(mystr)-CASE WHEN CHARINDEX('(',mystr)=0 THEN LEN(mystr) 
ELSE CHARINDEX('(',mystr)END +1) FROM docs

3 个答案:

答案 0 :(得分:1)

试试这个:

DECLARE @x NVARCHAR(20) = '123(A)';
SELECT CASE WHEN CHARINDEX('(', @x) = 0 THEN NULL ELSE RIGHT(@x, LEN(@x) - CHARINDEX('(', @x) + 1) END AS x

答案 1 :(得分:1)

在你的情况下,你在最后)之后什么都没有,所以你可以使用一些大数字来指出要获得多少个符号:

DECLARE @DataSource TABLE
(   
    [value] VARCHAR(48)
);

INSERT INTO @DataSource ([value])
VALUES ('123(0)')
      ,('233 (123)')
      ,('23 (A)')
      ,('2 (122)');

SELECT CASE WHEN  CHARINDEX('(', [value]) <> 0 THEN SUBSTRING([value], CHARINDEX('(', [value]), 100) ELSE '' END
FROM @DataSource;

如果在最终)之后有值:

DECLARE @DataSource TABLE
(   
    [value] VARCHAR(48)
);

INSERT INTO @DataSource ([value])
VALUES ('123(0) test')
      ,('233 (123) test 12')
      ,('23 (A)')
      ,('2 (122) sometthing');

SELECT SUBSTRING([value], CHARINDEX('(', [value]),  CHARINDEX(')', [value]) - CHARINDEX('(', [value]) + 1)
FROM @DataSource;

答案 2 :(得分:1)

如果对表格值函数开放,请考虑以下事项:

厌倦了接受和解析字符串(left(),right(),charindex(),...),我修改了一个解析函数来接受两个不相似的分隔符。

示例

Declare @YourTable table (mystr varchar(50))
Insert Into @YourTable values
('122'),
('123(0)'),
('233 (123)'),
('23 (A)'),
('2 (122)')

Select A.*
      ,NewVal = IsNull('('+B.RetVal+')','')   -- Adding back the ()'s
 From  @YourTable A
 Outer Apply [dbo].[tvf-Str-Extract](A.mystr,'(',')') B

<强>返回

mystr       NewVal
122 
123(0)      (0)
233 (123)   (123)
23 (A)      (A)
2 (122)     (122)

感兴趣的UDF

CREATE FUNCTION [dbo].[tvf-Str-Extract] (@String varchar(max),@Delimiter1 varchar(100),@Delimiter2 varchar(100))
Returns Table 
As
Return (  

with   cte1(N)   As (Select 1 From (Values(1),(1),(1),(1),(1),(1),(1),(1),(1),(1)) N(N)),
       cte2(N)   As (Select Top (IsNull(DataLength(@String),0)) Row_Number() over (Order By (Select NULL)) From (Select N=1 From cte1 N1,cte1 N2,cte1 N3,cte1 N4,cte1 N5,cte1 N6) A ),
       cte3(N)   As (Select 1 Union All Select t.N+DataLength(@Delimiter1) From cte2 t Where Substring(@String,t.N,DataLength(@Delimiter1)) = @Delimiter1),
       cte4(N,L) As (Select S.N,IsNull(NullIf(CharIndex(@Delimiter1,@String,s.N),0)-S.N,8000) From cte3 S)

Select RetSeq = Row_Number() over (Order By N)
      ,RetPos = N
      ,RetVal = left(RetVal,charindex(@Delimiter2,RetVal)-1) 
 From  (
        Select *,RetVal = Substring(@String, N, L) 
         From  cte4
       ) A
 Where charindex(@Delimiter2,RetVal)>1

)
/*
Max Length of String 1MM characters

Declare @String varchar(max) = 'Dear [[FirstName]] [[LastName]], ...'
Select * From [dbo].[tvf-Str-Extract] (@String,'[[',']]')
*/