在 Sql 服务器中按“\”拆分列值
Splitting column value by '\' in Sql server
我在 FileFullPath
列中有一些数据
Y:\dfs-dc-01\Split\Retail\Kroger\Kroger\FTP-FromClient\Oracle22-05-04\MSudaitemlov_20220503
Y:\dfs-dc-01\Split\Retail\Kroger\Kroger\FTP-FromClient\OracleABC22-05-04\FDERDMSudaitemlov_20220503
Y:\dfs-dc-01\Split\Retail\Kroger\Kroger\FTP-FromClient\OCSBAGF22-05-04\AASSSMSudaitemlov_20220503
我想要的部分是:
Oracle
OracleABC
OCSBAGF
字母是 dynamic
所以,我无法应用 Left,Right
函数,因为长度不同。我试图通过使用 STRING_SPLIT()
使用 '\'
拆分它,但它说:
Msg 195, Level 15, State 10, Line 18
'string_split' is not a recognized built-in function name.
您应该可以在 SQL Server 2016 中使用 STRING_SPLIT()
,但以下两种情况除外:
- 如果您没有正确调用该函数 - 许多人尝试将其作为标量函数 (
SELECT STRING_SPLIT(...
) 而不是 table-valued 函数 (SELECT * FROM STRING_SPLIT(...
) 来调用。它 returns 一个 table,所以你必须像 table 一样对待它。
- 如果您的数据库的兼容级别低于 130。在您无法更改兼容级别的情况下,这被称为 at the very top of the documentation, and I've given several workarounds in this tip。
但是STRING_SPLIT()
无论如何也解决不了这个问题...
...因为无法保证输出顺序,所以您永远无法可靠地确定哪个元素是倒数第三个。
无耻地借鉴我在this article中的工作,您可以创建以下简单函数:
CREATE FUNCTION dbo.SplitOrdered_JSON
(
@List nvarchar(4000),
@Delimiter nvarchar(255)
)
RETURNS table WITH SCHEMABINDING
AS
RETURN
(
SELECT [key], value FROM OPENJSON
(
CONCAT
(
N'["',
REPLACE(STRING_ESCAPE(@List, 'JSON'),
@Delimiter, N'","'),
N'"]')
) AS x
);
然后如果你在字符串中的倒数第三个元素之后,你可以在解析之前反转,然后在解析之后再次反转。例如
CREATE TABLE #f(ID int, FullFilePath nvarchar(4000));
INSERT #f VALUES
(1,N'Y:\dfs-dc-01\Split\Retail\Kroger\Kroger\FTP-FromClient\Oracle22-05-04\MSudaitemlov_20220503'),
(2,N'Y:\dfs-dc-01\Split\Retail\Kroger\Kroger\FTP-FromClient\OracleABC22-05-04\FDERDMSudaitemlov_20220503'),
(3,N'Y:\dfs-dc-01\Split\Retail\Kroger\Kroger\FTP-FromClient\OCSBAGF22-05-04\AASSSMSudaitemlov_20220503');
DECLARE @ElementOfInterest int = 3;
SELECT REVERSE(value)
FROM #f CROSS APPLY dbo.SplitOrdered_JSON(REVERSE(FullFilePath), N'\')
WHERE [key] = @ElementOfInterest - 1;
这是另一个完整覆盖的解决方案。
它将从 SQL Server 2012 开始运行。
它正在使用 XML 和 XQuery 进行标记化。不需要任何 User-Defined-Function (UDF).
SQL
-- DDL and sample data population, start
DECLARE @tbl TABLE (ID INT IDENTITY PRIMARY KEY, FullFilePath nvarchar(4000));
INSERT INTO @tbl (FullFilePath) VALUES
(N'Y:\dfs-dc-01\Split\Retail\Kroger\Kroger\FTP-FromClient\Oracle22-05-04\MSudaitemlov_20220503'),
(N'Y:\dfs-dc-01\Split\Retail\Kroger\Kroger\FTP-FromClient\OracleABC22-05-04\FDERDMSudaitemlov_20220503'),
(N'Y:\dfs-dc-01\Split\Retail\Kroger\Kroger\FTP-FromClient\OCSBAGF22-05-04\AASSSMSudaitemlov_20220503');
-- DDL and sample data population, end
DECLARE @separator CHAR(1) = '\'
, @token int = 8;
SELECT t.*
, c.value('(/root/r[sql:variable("@token")]/text())[1]', 'NVARCHAR(20)')
FROM @tbl AS t
CROSS APPLY (SELECT TRY_CAST('<root><r><![CDATA[' +
REPLACE(FullFilePath, @separator, ']]></r><r><![CDATA[') +
']]></r></root>' AS XML)) AS t1(c);
输出
+----+--------------------------------------------------------------------------------------------------------+------------------+
| ID | FullFilePath | (No column name) |
+----+--------------------------------------------------------------------------------------------------------+------------------+
| 1 | Y:\dfs-dc-01\Split\Retail\Kroger\Kroger\FTP-FromClient\Oracle22-05-04\MSudaitemlov_20220503 | Oracle |
| 2 | Y:\dfs-dc-01\Split\Retail\Kroger\Kroger\FTP-FromClient\OracleABC22-05-04\FDERDMSudaitemlov_20220503 | OracleABC |
| 3 | Y:\dfs-dc-01\Split\Retail\Kroger\Kroger\FTP-FromClient\OCSBAGF22-05-04\AASSSMSudaitemlov_20220503 | OCSBAGF |
+----+--------------------------------------------------------------------------------------------------------+------------------+
我在 FileFullPath
列中有一些数据
Y:\dfs-dc-01\Split\Retail\Kroger\Kroger\FTP-FromClient\Oracle22-05-04\MSudaitemlov_20220503
Y:\dfs-dc-01\Split\Retail\Kroger\Kroger\FTP-FromClient\OracleABC22-05-04\FDERDMSudaitemlov_20220503
Y:\dfs-dc-01\Split\Retail\Kroger\Kroger\FTP-FromClient\OCSBAGF22-05-04\AASSSMSudaitemlov_20220503
我想要的部分是:
Oracle
OracleABC
OCSBAGF
字母是 dynamic
所以,我无法应用 Left,Right
函数,因为长度不同。我试图通过使用 STRING_SPLIT()
使用 '\'
拆分它,但它说:
Msg 195, Level 15, State 10, Line 18
'string_split' is not a recognized built-in function name.
您应该可以在 SQL Server 2016 中使用 STRING_SPLIT()
,但以下两种情况除外:
- 如果您没有正确调用该函数 - 许多人尝试将其作为标量函数 (
SELECT STRING_SPLIT(...
) 而不是 table-valued 函数 (SELECT * FROM STRING_SPLIT(...
) 来调用。它 returns 一个 table,所以你必须像 table 一样对待它。 - 如果您的数据库的兼容级别低于 130。在您无法更改兼容级别的情况下,这被称为 at the very top of the documentation, and I've given several workarounds in this tip。
但是STRING_SPLIT()
无论如何也解决不了这个问题...
...因为无法保证输出顺序,所以您永远无法可靠地确定哪个元素是倒数第三个。
无耻地借鉴我在this article中的工作,您可以创建以下简单函数:
CREATE FUNCTION dbo.SplitOrdered_JSON
(
@List nvarchar(4000),
@Delimiter nvarchar(255)
)
RETURNS table WITH SCHEMABINDING
AS
RETURN
(
SELECT [key], value FROM OPENJSON
(
CONCAT
(
N'["',
REPLACE(STRING_ESCAPE(@List, 'JSON'),
@Delimiter, N'","'),
N'"]')
) AS x
);
然后如果你在字符串中的倒数第三个元素之后,你可以在解析之前反转,然后在解析之后再次反转。例如
CREATE TABLE #f(ID int, FullFilePath nvarchar(4000));
INSERT #f VALUES
(1,N'Y:\dfs-dc-01\Split\Retail\Kroger\Kroger\FTP-FromClient\Oracle22-05-04\MSudaitemlov_20220503'),
(2,N'Y:\dfs-dc-01\Split\Retail\Kroger\Kroger\FTP-FromClient\OracleABC22-05-04\FDERDMSudaitemlov_20220503'),
(3,N'Y:\dfs-dc-01\Split\Retail\Kroger\Kroger\FTP-FromClient\OCSBAGF22-05-04\AASSSMSudaitemlov_20220503');
DECLARE @ElementOfInterest int = 3;
SELECT REVERSE(value)
FROM #f CROSS APPLY dbo.SplitOrdered_JSON(REVERSE(FullFilePath), N'\')
WHERE [key] = @ElementOfInterest - 1;
这是另一个完整覆盖的解决方案。
它将从 SQL Server 2012 开始运行。
它正在使用 XML 和 XQuery 进行标记化。不需要任何 User-Defined-Function (UDF).
SQL
-- DDL and sample data population, start
DECLARE @tbl TABLE (ID INT IDENTITY PRIMARY KEY, FullFilePath nvarchar(4000));
INSERT INTO @tbl (FullFilePath) VALUES
(N'Y:\dfs-dc-01\Split\Retail\Kroger\Kroger\FTP-FromClient\Oracle22-05-04\MSudaitemlov_20220503'),
(N'Y:\dfs-dc-01\Split\Retail\Kroger\Kroger\FTP-FromClient\OracleABC22-05-04\FDERDMSudaitemlov_20220503'),
(N'Y:\dfs-dc-01\Split\Retail\Kroger\Kroger\FTP-FromClient\OCSBAGF22-05-04\AASSSMSudaitemlov_20220503');
-- DDL and sample data population, end
DECLARE @separator CHAR(1) = '\'
, @token int = 8;
SELECT t.*
, c.value('(/root/r[sql:variable("@token")]/text())[1]', 'NVARCHAR(20)')
FROM @tbl AS t
CROSS APPLY (SELECT TRY_CAST('<root><r><![CDATA[' +
REPLACE(FullFilePath, @separator, ']]></r><r><![CDATA[') +
']]></r></root>' AS XML)) AS t1(c);
输出
+----+--------------------------------------------------------------------------------------------------------+------------------+
| ID | FullFilePath | (No column name) |
+----+--------------------------------------------------------------------------------------------------------+------------------+
| 1 | Y:\dfs-dc-01\Split\Retail\Kroger\Kroger\FTP-FromClient\Oracle22-05-04\MSudaitemlov_20220503 | Oracle |
| 2 | Y:\dfs-dc-01\Split\Retail\Kroger\Kroger\FTP-FromClient\OracleABC22-05-04\FDERDMSudaitemlov_20220503 | OracleABC |
| 3 | Y:\dfs-dc-01\Split\Retail\Kroger\Kroger\FTP-FromClient\OCSBAGF22-05-04\AASSSMSudaitemlov_20220503 | OCSBAGF |
+----+--------------------------------------------------------------------------------------------------------+------------------+