これが1つの試みですが、私が言ったように、ネイティブT-SQLで高速なソリューションが得られるとは思いません。
まず、数値テーブルがまだない場合は、次のように作成します。
SET NOCOUNT ON;
DECLARE @UpperLimit int = 4000;
;WITH n AS
(
SELECT rn = ROW_NUMBER() OVER (ORDER BY s1.[object_id])
FROM sys.all_objects AS s1
CROSS JOIN sys.all_objects AS s2
)
SELECT [Number] = rn - 1
INTO dbo.Numbers FROM n
WHERE rn <= @UpperLimit + 1;
CREATE UNIQUE CLUSTERED INDEX n ON dbo.Numbers([Number]);
次に、2つの関数を作成します。1つは文字列をテーブルに分割し、もう1つは最初の関数の結果を再結合しますが、後続の重複は無視します。
CREATE FUNCTION dbo.SplitStrings
(
@List nvarchar(4000),
@Delim char(1)
)
RETURNS TABLE
AS
RETURN ( SELECT
rn = ROW_NUMBER() OVER (ORDER BY CHARINDEX(@Delim, @List + @Delim)),
[Value] = LTRIM(RTRIM(SUBSTRING(@List, [Number],
CHARINDEX(@Delim, @List + @Delim, [Number]) - [Number])))
FROM dbo.Numbers
WHERE Number <= LEN(@List)
AND SUBSTRING(@Delim + @List, [Number], 1) = @Delim
);
GO
2番目の機能:
CREATE FUNCTION dbo.RebuildString
(
@List nvarchar(4000),
@Delim char(1)
)
RETURNS nvarchar(4000)
AS
BEGIN
RETURN ( SELECT newval = STUFF((
SELECT @Delim + x.[Value] FROM dbo.SplitStrings(@List, @Delim) AS x
LEFT OUTER JOIN dbo.SplitStrings(@List, @Delim) AS x2
ON x.rn = x2.rn + 1
WHERE (x2.rn IS NULL OR x.value <> x2.value)
ORDER BY x.rn
FOR XML PATH(''), TYPE).value(N'./text()[1]', N'nvarchar(max)'), 1, 1, N'')
);
END
GO
これで、質問で指定した2つのサンプルに対して試してみることができます。
;WITH cte(colname) AS
(
SELECT 'Jhon\Jhon\Jane\Mary\Bob'
UNION ALL SELECT 'Mary\Jane\Mary\Bob'
)
SELECT dbo.RebuildString(colname, '\')
FROM cte;
結果:
Jhon\Jane\Mary\Bob
Mary\Jane\Mary\Bob
ただし、使用を決定する前に、通常のデータサイズに対してこれを徹底的にテストすることを強く、強く、強くお勧めします。