在 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(),但以下两种情况除外:

  1. 如果您没有正确调用该函数 - 许多人尝试将其作为标量函数 (SELECT STRING_SPLIT(...) 而不是 table-valued 函数 (SELECT * FROM STRING_SPLIT(...) 来调用。它 returns 一个 table,所以你必须像 table 一样对待它。
  2. 如果您的数据库的兼容级别低于 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          |
+----+--------------------------------------------------------------------------------------------------------+------------------+