[英]Extract string between double quotes in SQL
我有一个字符串,我需要返回双引号之间的字符
'((“名称 1”和“名称 2”)或“名称 3”)
我需要返回
Name 1
Name 2
Name 3
我已经使用下面的 function 来拆分字符串,但我得到了 (( 以及 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并返回所需的output?
谢谢
这是一种递归方法
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进行分组和重新连接。
试试看; 我将调试变量保留在输出表中
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
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;
您需要使用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()
。
附加变体,避免循环:
DECLARE @testData VARCHAR(250) = '(("Name 1" and "Name 2") or "Name 3")'
DECLARE @delimeter VARCHAR(10) = '"';
;WITH
tally AS --create sequence 1 to string Length
(
SELECT n = 1
UNION ALL
SELECT n +1
FROM tally
WHERE n <= LEN(@testData)
),
cte AS
(
SELECT T.N , ROW_NUMBER() OVER ( ORDER BY T.N ) AS RN
FROM tally AS T
WHERE SUBSTRING(@testData, T.N, LEN(@delimeter)) = @delimeter
)
SELECT REPLACE(SUBSTRING(@testData, COALESCE(R.N, LEN(@delimeter), 1),
L.N - COALESCE(R.N, LEN(@delimeter), 1)),@delimeter,'') AS part
FROM cte AS L
LEFT JOIN cte AS R ON L.RN = R.RN+1
WHERE L.RN%2=0
OPTION (MAXRECURSION 1000)
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.