在 RIGHT() 或 SUBSTRING() 中使用 CHARINDEX() 拆分字符串 return 不正确的结果
Split string by using CHARINDEX() in RIGHT() or SUBSTRING() return incorrect result
我想将一栏分成两栏。我想 select 单元格值 '('
的值所以这是我的要求:
输入字符串:
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
工作原理:我想 select 索引我首先找到 '('
的位置,然后是它旁边的 select 值。由于 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
这里的第一个元素没有被 select 编辑,所以我将 +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
试试这个:
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
在你的情况下,你在最后一个 )
之后什么都没有,所以你可以使用一些大数字来指出要获得多少个符号:
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;
如果对 Table 值函数开放,请考虑以下事项:
厌倦了提取和解析字符串(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
Returns
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,'[[',']]')
*/
我想将一栏分成两栏。我想 select 单元格值 '('
的值所以这是我的要求:
输入字符串:
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
工作原理:我想 select 索引我首先找到 '('
的位置,然后是它旁边的 select 值。由于 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
这里的第一个元素没有被 select 编辑,所以我将 +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
试试这个:
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
在你的情况下,你在最后一个 )
之后什么都没有,所以你可以使用一些大数字来指出要获得多少个符号:
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;
如果对 Table 值函数开放,请考虑以下事项:
厌倦了提取和解析字符串(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
Returns
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,'[[',']]')
*/