T-SQL用 - 和空格

时间:2016-07-07 12:22:28

标签: tsql split charindex

我在使用T-SQL时遇到了困难,我想知道是否有人能让我指出正确的方向。 我有以下变量叫做@input

    DECLARE @input nvarchar(100);
    SET @input= '27364 - John Smith';
   -- SET @input= '27364 - John Andrew Smith';

如果字符串包含MiddleName,我需要将此字符串拆分为3个部分(ID,Firstname和LastName)或4。出于安全原因,我无法使用功能。

我的aproach是使用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存在,代码必须足够聪明才能添加第四个分割。

有什么想法吗?

提前致谢

2 个答案:

答案 0 :(得分:3)

希望这是规范化项目的一部分。这个数据打破1NF,其中一个真的应该避免......

尝试这样

优点

  • 类型安全值
  • ad-hoc SQL
  • 基于设置

如果您愿意,可以使用CASE WHEN检查最后一部分是NULL,并在这种情况下将Part2放入Part3 ......

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'&amp;'),N'<',N'&lt;'),N'>',N'&gt;'),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

答案 1 :(得分:0)

SQL Server 2016有一个名为STRING_SPLIT()

的新内置函数

假设创建内置函数,但不允许使用CLR函数:

% Set up parameters
nT = 200; N = 50; w = 0.05;
% Set up results matrix, including initial conditions by row 1 (all 0)
d = zeros(nT, N);
% Loop, storing results to d
for t = 2:nT
    d(t,:) = d(t-1,:) + w*rand(1,N);
end

用法:

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])

希望有帮助!