我有一个字符串,我需要返回双引号之间的字符
'(((“名称1”和“名称2”)或“名称3”)
我需要回来
Name 1
Name 2
Name 3
我已经使用下面的函数来分割字符串,但是我得到了((和Or与AND等..这是我不想要的,但不幸的是,我无法确定所有其他可能的字符包含在内,因此删除或替换它们实际上是不可行的。
ALTER FUNCTION [dbo].[fn_SplitString]
(
@string NVARCHAR(MAX),
@delimiter CHAR(1)
)
RETURNS @output TABLE(ID int, splitdata NVARCHAR(MAX)
)
BEGIN
DECLARE @start INT, @end INT, @Count INT
set @Count = 1
SELECT @start = 1, @end = CHARINDEX(@delimiter, @string)
WHILE @start < LEN(@string) + 1 BEGIN
IF @end = 0
SET @end = LEN(@string) + 1
INSERT INTO @output (ID, splitdata)
VALUES(@Count, SUBSTRING(@string, @start, @end - @start))
SET @start = @end + 1
SET @end = CHARINDEX(@delimiter, @string, @start)
Set @Count = @Count+1
END
RETURN
END
我知道这段代码将返回2个分隔符之间的字符串
substring( LEFT(@String, charindex(']', @String)-1), CHARINDEX('[', @String) + len('['), LEN(@String))
有什么方法可以合并2并返回所需的输出?
谢谢
答案 0 :(得分:5)
这是一种递归方法
DECLARE @s VARCHAR(100)='(("Name 1" and "Name 2") or "Name 3")';
WITH recCTE AS
(
SELECT 1 AS Position
,SUBSTRING(@s,1,1) AS CharAtPos
,CASE WHEN SUBSTRING(@s,1,1)='"' THEN 0 ELSE -1 END AS QuoteGroup
,CASE WHEN SUBSTRING(@s,1,1)='"' THEN 1 ELSE 0 END AS QuoteIsOpen
UNION ALL
SELECT r.Position+1
,SUBSTRING(@s,r.Position+1,1)
,CASE WHEN SUBSTRING(@s,r.Position+1,1)='"' THEN CASE WHEN r.QuoteIsOpen=0 THEN r.QuoteGroup+1 ELSE r.QuoteGroup END ELSE r.QuoteGroup END AS QuoteGroup
,CASE WHEN SUBSTRING(@s,r.Position+1,1)='"' THEN CASE WHEN r.QuoteIsOpen=0 THEN 1 ELSE 0 END ELSE r.QuoteIsOpen END AS QuoteIsOpen
FROM recCTE r
WHERE r.Position+1<=LEN(REPLACE(@s,' ','*'))
)
SELECT r.QuoteGroup
,(
SELECT CharAtPos AS [*]
FROM recCTE r2
WHERE r2.QuoteGroup=r.QuoteGroup AND r2.QuoteIsOpen=1 AND r2.CharAtPos<>'"'
ORDER BY r2.Position
FOR XML PATH(''),TYPE).value('.','varchar(100)')
FROM recCTE r
WHERE r.QuoteGroup>=0
GROUP BY QuoteGroup;
递归CTE将逐字符遍历您的字符串。它将检查报价并跟踪处于打开状态或处于关闭状态。依赖于此,所有带有 open 标志的值都将通过XML进行分组和重新连接。
答案 1 :(得分:1)
尝试一下;我将调试变量保留在输出表中
ALTER FUNCTION [dbo].[fn_SplitString]
(
@string NVARCHAR(MAX),
@delimiter CHAR(1)
)
RETURNS @output TABLE
(
[Id] INT,
[Start] INT,
[End] INT,
[Length] INT,
[Data] NVARCHAR(MAX)
)
BEGIN
DECLARE @count INT, @start INT, @end INT
SELECT @count = 1, @end = 0,
@start = CHARINDEX(@delimiter, @string)
WHILE @start > 0 BEGIN
SELECT @end = CHARINDEX(@delimiter, @string, @start + 1)
INSERT INTO @output ([Id], [Start], [End], [Length], [Data])
VALUES (@count, @start, @end, @end - @start - 1,
SUBSTRING(@string, @start + 1, @end - @start - 1))
SELECT @start = CHARINDEX(@delimiter, @string, @end + 1),
@count = @count + 1
END
RETURN
END
或者这基于接收两个不同定界符的想法:
ALTER FUNCTION [dbo].[fn_SplitString]
(
@string NVARCHAR(MAX),
@delimiter1 NVARCHAR(MAX),
@delimiter2 NVARCHAR(MAX)
)
RETURNS @output TABLE
(
[Id] INT,
[Start] INT,
[End] INT,
[Length] INT,
[Data] NVARCHAR(MAX)
)
BEGIN
DECLARE @count INT, @start INT, @end INT
SELECT @count = 1, @end = 0
SELECT @start = CHARINDEX(@delimiter1, @string)
SELECT @end = CHARINDEX(@delimiter2, @string, @start + 1)
WHILE @start > 0 AND @end > 0 BEGIN
INSERT INTO @output ([Id], [Start], [End], [Length], [Data])
VALUES (@count, @start, @end, @end - @start - 1,
SUBSTRING(@string, @start + 1, @end - @start - 1))
SELECT @start = CHARINDEX(@delimiter1, @string, @end + 1)
SELECT @end = CHARINDEX(@delimiter2, @string, @start + 1),
@count = @count + 1
END
RETURN
END
答案 2 :(得分:1)
此修改版的Jeff Moden的splitter函数应为您提供所需的内容。这样可以避免循环,并且无需查找和替换某些字符串或字符。
CREATE FUNCTION dbo._SplitStrings
(
@List NVARCHAR(MAX),
@Delimiter NVARCHAR(255)
)
RETURNS TABLE
WITH SCHEMABINDING AS
RETURN
WITH E1(N)
AS
(
SELECT 1 UNION ALL SELECT 1 UNION ALL SELECT 1 UNION ALL SELECT 1
UNION ALL SELECT 1 UNION ALL SELECT 1 UNION ALL SELECT 1
UNION ALL SELECT 1 UNION ALL SELECT 1 UNION ALL SELECT 1
),
E2(N) AS ( SELECT 1 FROM E1 a, E1 b ),
E4(N) AS ( SELECT 1 FROM E2 a, E2 b ),
E42(N) AS ( SELECT 1 FROM E4 a, E2 b ),
cteTally(N)
AS
(
SELECT 0 UNION ALL SELECT TOP (DATALENGTH(ISNULL(@List,1)))
ROW_NUMBER() OVER (ORDER BY (SELECT NULL)) FROM E42),
cteStart(N1) AS (SELECT t.N+1 FROM cteTally t
WHERE (SUBSTRING(@List,t.N,1) = @Delimiter OR t.N = 0)),
cteSplitByDelimiter AS
(
SELECT s.N1,
SUBSTRING(@List, s.N1 - 1, 1) AS [StartDelimiter],
SUBSTRING(@List , s.N1 + ISNULL(NULLIF(CHARINDEX(@Delimiter,@List,s.N1),0)-s.N1,8000), + 1) AS [EndDelimiter],
SUBSTRING(@List, s.N1, ISNULL(NULLIF(CHARINDEX(@Delimiter,@List,s.N1),0)-s.N1,8000)) AS [Item]
FROM cteStart s
),
cteList AS
(
SELECT N1
,Item
,ROW_NUMBER() OVER (ORDER BY N1) % 2 AS ExpectedItem
FROM cteSplitByDelimiter sd
WHERE sd.StartDelimiter = @Delimiter and sd.EndDelimiter = @Delimiter
)
SELECT Item
FROM cteList
WHERE ExpectedItem = 1;
答案 3 :(得分:0)
您需要使用replace()
函数,然后将其传递给函数参数:
declare @string varchar(255) = '(("Name 1" and "Name 2") or "Name 3")'
set @string = replace(replace(replace(replace(replace(@string, '(', ''), ')', ''), '"', ''), 'and', ','), 'or', ',')
select *
from [dbo].[fn_SplitString](@string, ',') spt;
如果您使用的是最新版本的SQL Server,则可以使用TRANSLATE()代替replace()
。