T-SQL 将字符串拆分为 - 和 space
T-SQL split string by - and space
我在使用 T-SQL 时遇到了困难,我想知道是否有人可以为我指明正确的轨道。
我有以下名为 @input
的变量
DECLARE @input nvarchar(100);
SET @input= '27364 - John Smith';
-- SET @input= '27364 - John Andrew Smith';
我需要将此字符串拆分为 3 个部分(ID、名字和姓氏)或 4 个(如果字符串包含中间名)。出于安全原因,我无法使用函数。
我的方法是使用 Substring 和 Charindex。
SET @Id = SUBSTRING(@input, 1, CASE CHARINDEX('-', @input)
WHEN 0
THEN LEN(@input)
ELSE
CHARINDEX('-', @input) - 2
END);
SET @FirstName = SUBSTRING(@input, CASE CHARINDEX(' ', @input)
WHEN 0
THEN LEN(@input) + 1
ELSE
CHARINDEX(' ', @input) + 1
END, 1000);
SET @LastName = SUBSTRING(@input, CASE CHARINDEX(' ', @input)
WHEN 0
THEN LEN(@input) + 1
ELSE
CHARINDEX('0', @input) + 1
END, 1000);
Select @PartyCode,@FirstName,@LastName
我被卡住了,因为我不知道如何继续,而且如果 Middlename 存在,代码必须足够聪明才能添加第四个拆分。
有什么想法吗?
提前致谢
希望这是标准化项目的一部分。该数据打破了 1NF,确实应该避免这种情况...
像这样尝试
优点
- 类型安全值
- 临时 SQL
- 基于集合
如果需要,您可以使用 CASE WHEN
检查最后一部分是否为 NULL
,并在这种情况下将第 2 部分放入第 3 部分...
DECLARE @input table(teststring nvarchar(100));
INSERT INTO @input VALUES
(N'27364 - John Smith'),(N'27364 - John Andrew Smith');
WITH Splitted AS
(
SELECT CAST(N'<x>' + REPLACE(REPLACE(REPLACE(REPLACE(REPLACE(teststring,N' - ',N' '),N'&',N'&'),N'<',N'<'),N'>',N'>'),N' ',N'</x><x>') + N'</x>' AS XML) testXML
FROM @input
)
SELECT testXML.value('/x[1]','int') AS Number
,testXML.value('/x[2]','nvarchar(max)') AS Part1
,testXML.value('/x[3]','nvarchar(max)') AS Part2
,testXML.value('/x[4]','nvarchar(max)') AS Part3
FROM Splitted
结果
Number Part1 Part2 Part3
27364 John Smith NULL
27364 John Andrew Smith
SQL Server 2016 有一个名为 STRING_SPLIT()
的新内置函数
假设创建内置函数,但不允许使用 CLR 函数:
CREATE FUNCTION dbo.WORD_SPLIT
(
@String AS nvarchar(4000)
)
RETURNS TABLE
AS
RETURN
(
WITH Spaces AS
(
SELECT Spaced.[value], ROW_NUMBER() OVER (PARTITION BY 1 ORDER BY (SELECT 1)) AS ordinal
FROM STRING_SPLIT(@String, ' ') AS Spaced
)
, Tabs AS
(
SELECT Tabbed.[value], ROW_NUMBER() OVER (PARTITION BY 1 ORDER BY s.ordinal, (SELECT 1)) AS ordinal
FROM Spaces AS s
CROSS APPLY STRING_SPLIT(s.[value], ' ') AS Tabbed
)
, NewLines1 AS
(
SELECT NewLined1.[value], ROW_NUMBER() OVER (PARTITION BY 1 ORDER BY t.ordinal, (SELECT 1)) AS ordinal
FROM Tabs AS t
CROSS APPLY STRING_SPLIT(t.[value], CHAR(13)) AS NewLined1
)
, NewLines2 AS
(
SELECT NewLined2.[value], ROW_NUMBER() OVER (PARTITION BY 1 ORDER BY nl1.ordinal, (SELECT 1)) AS ordinal
FROM NewLines1 AS nl1
CROSS APPLY STRING_SPLIT(nl1.[value], CHAR(10)) AS NewLined2
)
SELECT LTRIM(RTRIM(nl2.[value])) AS [value], ROW_NUMBER() OVER (PARTITION BY 1 ORDER BY nl2.ordinal, (SELECT 1)) AS ordinal
FROM NewLines2 AS nl2
WHERE LTRIM(RTRIM(nl2.[value])) <> ''
)
GO
用法:
-- Not Normailized
SELECT i.*, split.[value], split.[ordinal]
FROM @input AS i
CROSS APPLY dbo.WORD_SPLIT(i.teststring) AS split
-- Normalized
;WITH Splitted AS
(
SELECT split.[value], split.[ordinal]
FROM @input AS i
CROSS APPLY dbo.WORD_SPLIT(i.teststring) AS split
)
SELECT *
FROM (SELECT [value], 'part' + CONVERT(nvarchar(20), [ordinal]) AS [parts] FROM Splitted) AS s
PIVOT (MAX([value]) FOR [parts] IN ([part1], [part2], [part3], [part4])
或者假设,根据安全性,不允许您进行架构更改:
WITH Splitting AS
(
SELECT teststring AS [value]
FROM @input
)
WITH Spaces AS
(
SELECT Spaced.[value], ROW_NUMBER() OVER (PARTITION BY 1 ORDER BY (SELECT 1)) AS ordinal
FROM Splitting AS sp
CROSS APPLY STRING_SPLIT(sp.[value], ' ') AS Spaced
)
, Tabs AS
(
SELECT Tabbed.[value], ROW_NUMBER() OVER (PARTITION BY 1 ORDER BY s.ordinal, (SELECT 1)) AS ordinal
FROM Spaces AS s
CROSS APPLY STRING_SPLIT(s.[value], ' ') AS Tabbed
)
, NewLines1 AS
(
SELECT NewLined1.[value], ROW_NUMBER() OVER (PARTITION BY 1 ORDER BY t.ordinal, (SELECT 1)) AS ordinal
FROM Tabs AS t
CROSS APPLY STRING_SPLIT(t.[value], CHAR(13)) AS NewLined1
)
, NewLines2 AS
(
SELECT NewLined2.[value], ROW_NUMBER() OVER (PARTITION BY 1 ORDER BY nl1.ordinal, (SELECT 1)) AS ordinal
FROM NewLines1 AS nl1
CROSS APPLY STRING_SPLIT(nl1.[value], CHAR(10)) AS NewLined2
)
, Splitted AS
(
SELECT LTRIM(RTRIM(nl2.[value])) AS [teststring], ROW_NUMBER() OVER (PARTITION BY 1 ORDER BY nl2.ordinal, (SELECT 1)) AS ordinal
FROM NewLines2 AS nl2
WHERE LTRIM(RTRIM(nl2.[value])) <> ''
)
SELECT *
FROM (SELECT [value], 'part' + CONVERT(nvarchar(20), [ordinal]) AS [parts] FROM Splitted) AS s
PIVOT (MAX([value]) FOR [parts] IN ([part1], [part2], [part3], [part4])
希望对您有所帮助!
我在使用 T-SQL 时遇到了困难,我想知道是否有人可以为我指明正确的轨道。 我有以下名为 @input
的变量 DECLARE @input nvarchar(100);
SET @input= '27364 - John Smith';
-- SET @input= '27364 - John Andrew Smith';
我需要将此字符串拆分为 3 个部分(ID、名字和姓氏)或 4 个(如果字符串包含中间名)。出于安全原因,我无法使用函数。
我的方法是使用 Substring 和 Charindex。
SET @Id = SUBSTRING(@input, 1, CASE CHARINDEX('-', @input)
WHEN 0
THEN LEN(@input)
ELSE
CHARINDEX('-', @input) - 2
END);
SET @FirstName = SUBSTRING(@input, CASE CHARINDEX(' ', @input)
WHEN 0
THEN LEN(@input) + 1
ELSE
CHARINDEX(' ', @input) + 1
END, 1000);
SET @LastName = SUBSTRING(@input, CASE CHARINDEX(' ', @input)
WHEN 0
THEN LEN(@input) + 1
ELSE
CHARINDEX('0', @input) + 1
END, 1000);
Select @PartyCode,@FirstName,@LastName
我被卡住了,因为我不知道如何继续,而且如果 Middlename 存在,代码必须足够聪明才能添加第四个拆分。
有什么想法吗?
提前致谢
希望这是标准化项目的一部分。该数据打破了 1NF,确实应该避免这种情况...
像这样尝试
优点
- 类型安全值
- 临时 SQL
- 基于集合
如果需要,您可以使用 CASE WHEN
检查最后一部分是否为 NULL
,并在这种情况下将第 2 部分放入第 3 部分...
DECLARE @input table(teststring nvarchar(100));
INSERT INTO @input VALUES
(N'27364 - John Smith'),(N'27364 - John Andrew Smith');
WITH Splitted AS
(
SELECT CAST(N'<x>' + REPLACE(REPLACE(REPLACE(REPLACE(REPLACE(teststring,N' - ',N' '),N'&',N'&'),N'<',N'<'),N'>',N'>'),N' ',N'</x><x>') + N'</x>' AS XML) testXML
FROM @input
)
SELECT testXML.value('/x[1]','int') AS Number
,testXML.value('/x[2]','nvarchar(max)') AS Part1
,testXML.value('/x[3]','nvarchar(max)') AS Part2
,testXML.value('/x[4]','nvarchar(max)') AS Part3
FROM Splitted
结果
Number Part1 Part2 Part3
27364 John Smith NULL
27364 John Andrew Smith
SQL Server 2016 有一个名为 STRING_SPLIT()
的新内置函数假设创建内置函数,但不允许使用 CLR 函数:
CREATE FUNCTION dbo.WORD_SPLIT
(
@String AS nvarchar(4000)
)
RETURNS TABLE
AS
RETURN
(
WITH Spaces AS
(
SELECT Spaced.[value], ROW_NUMBER() OVER (PARTITION BY 1 ORDER BY (SELECT 1)) AS ordinal
FROM STRING_SPLIT(@String, ' ') AS Spaced
)
, Tabs AS
(
SELECT Tabbed.[value], ROW_NUMBER() OVER (PARTITION BY 1 ORDER BY s.ordinal, (SELECT 1)) AS ordinal
FROM Spaces AS s
CROSS APPLY STRING_SPLIT(s.[value], ' ') AS Tabbed
)
, NewLines1 AS
(
SELECT NewLined1.[value], ROW_NUMBER() OVER (PARTITION BY 1 ORDER BY t.ordinal, (SELECT 1)) AS ordinal
FROM Tabs AS t
CROSS APPLY STRING_SPLIT(t.[value], CHAR(13)) AS NewLined1
)
, NewLines2 AS
(
SELECT NewLined2.[value], ROW_NUMBER() OVER (PARTITION BY 1 ORDER BY nl1.ordinal, (SELECT 1)) AS ordinal
FROM NewLines1 AS nl1
CROSS APPLY STRING_SPLIT(nl1.[value], CHAR(10)) AS NewLined2
)
SELECT LTRIM(RTRIM(nl2.[value])) AS [value], ROW_NUMBER() OVER (PARTITION BY 1 ORDER BY nl2.ordinal, (SELECT 1)) AS ordinal
FROM NewLines2 AS nl2
WHERE LTRIM(RTRIM(nl2.[value])) <> ''
)
GO
用法:
-- Not Normailized
SELECT i.*, split.[value], split.[ordinal]
FROM @input AS i
CROSS APPLY dbo.WORD_SPLIT(i.teststring) AS split
-- Normalized
;WITH Splitted AS
(
SELECT split.[value], split.[ordinal]
FROM @input AS i
CROSS APPLY dbo.WORD_SPLIT(i.teststring) AS split
)
SELECT *
FROM (SELECT [value], 'part' + CONVERT(nvarchar(20), [ordinal]) AS [parts] FROM Splitted) AS s
PIVOT (MAX([value]) FOR [parts] IN ([part1], [part2], [part3], [part4])
或者假设,根据安全性,不允许您进行架构更改:
WITH Splitting AS
(
SELECT teststring AS [value]
FROM @input
)
WITH Spaces AS
(
SELECT Spaced.[value], ROW_NUMBER() OVER (PARTITION BY 1 ORDER BY (SELECT 1)) AS ordinal
FROM Splitting AS sp
CROSS APPLY STRING_SPLIT(sp.[value], ' ') AS Spaced
)
, Tabs AS
(
SELECT Tabbed.[value], ROW_NUMBER() OVER (PARTITION BY 1 ORDER BY s.ordinal, (SELECT 1)) AS ordinal
FROM Spaces AS s
CROSS APPLY STRING_SPLIT(s.[value], ' ') AS Tabbed
)
, NewLines1 AS
(
SELECT NewLined1.[value], ROW_NUMBER() OVER (PARTITION BY 1 ORDER BY t.ordinal, (SELECT 1)) AS ordinal
FROM Tabs AS t
CROSS APPLY STRING_SPLIT(t.[value], CHAR(13)) AS NewLined1
)
, NewLines2 AS
(
SELECT NewLined2.[value], ROW_NUMBER() OVER (PARTITION BY 1 ORDER BY nl1.ordinal, (SELECT 1)) AS ordinal
FROM NewLines1 AS nl1
CROSS APPLY STRING_SPLIT(nl1.[value], CHAR(10)) AS NewLined2
)
, Splitted AS
(
SELECT LTRIM(RTRIM(nl2.[value])) AS [teststring], ROW_NUMBER() OVER (PARTITION BY 1 ORDER BY nl2.ordinal, (SELECT 1)) AS ordinal
FROM NewLines2 AS nl2
WHERE LTRIM(RTRIM(nl2.[value])) <> ''
)
SELECT *
FROM (SELECT [value], 'part' + CONVERT(nvarchar(20), [ordinal]) AS [parts] FROM Splitted) AS s
PIVOT (MAX([value]) FOR [parts] IN ([part1], [part2], [part3], [part4])
希望对您有所帮助!