来自 SQL 服务器中字符串的子字符串,如果符号存在,则在符号之后到字段末尾

Substring from a String in SQL Server after a symbol to the end of the field if the symbol exists

我查询了 ReportServer 数据库中的目录以获取报表服务器中存在的文件夹列表。所以我得到的结果如下所示:

[Path]
/Admin
/Compliance/Self Serve/Dublin
/Directors/Daily Reports

因此,顶级文件夹可以有一个正斜杠,顶级文件夹可以有两个正斜杠,下一级文件夹可以有 3 个或更多正斜杠。

我需要把它分成两部分。第一列应该只是没有起始正斜杠的顶级文件夹名称,第二部分应该是下一级文件夹结构的其余部分,例如

[Folder]         [Subfolders]
Admin            
Compliance       Self Serve/Dublin
Directors        Daily Reports

有很多方法可以获取符号前后的字符串来满足我的部分需求,但是顶级文件夹的问题让我很困惑,那里只有一个正斜杠。

拼命接收所有建议。

请尝试以下解决方案。

它基于标记化的想法。

  • 第一个标记(XPath 谓词 [1])将是根文件夹。
  • 其余标记(XPath 谓词 [position() gt 1])是子文件夹。

SQL

-- DDL and sample data population, start
DECLARE @tbl TABLE  (ID INT IDENTITY PRIMARY KEY, [path] NVARCHAR(MAX));
INSERT INTO @tbl (path) VALUES
('/Admin'),
('/Compliance/Self Serve/Dublin'),
('/Directors/Daily Reports'),
('//Directors/Daily Reports/Monday/Tuesday');
-- DDL and sample data population, end

DECLARE @separator CHAR(1) = '/';

WITH rs AS
(
    SELECT * 
        , TRY_CAST('<root><x><![CDATA[' + 
          REPLACE([path], @separator, ']]></x><x><![CDATA[') + 
          ']]></x></root>' AS XML) AS xmldata
    FROM @tbl
)
SELECT ID, [Path]
    , xmldata.value('(/root/x[text()][1]/text())[1]', 'NVARCHAR(100)') AS [Folder] 
    , REPLACE(xmldata.query('
        for $x in /root/x[text()][position() gt 1]
        return if ($x is (/root/x[position() = last()])[1]) then data($x)
            else concat($x, sql:variable("@separator"))
    ').value('text()[1]', 'NVARCHAR(MAX)'), '/ ', '/') AS [Subfolders]
FROM rs;

输出

+----+------------------------------------------+------------+------------------------------+
| ID |                   Path                   |   Folder   |          Subfolders          |
+----+------------------------------------------+------------+------------------------------+
|  1 | /Admin                                   | Admin      | NULL                         |
|  2 | /Compliance/Self Serve/Dublin            | Compliance | Self Serve/Dublin            |
|  3 | /Directors/Daily Reports                 | Directors  | Daily Reports                |
|  4 | //Directors/Daily Reports/Monday/Tuesday | Directors  | Daily Reports/Monday/Tuesday |
+----+------------------------------------------+------------+------------------------------+

我会保证目录名称以“/”字符结尾,这样您就可以选择简单的解决方案(例如 SUBSTRING + CHARINDEX)。

示例:

DECLARE @SEP VARCHAR(1) = '/'
DECLARE @CATALOG TABLE ( [Path] VARCHAR(200) )

INSERT INTO @CATALOG ([Path]) 
VALUES  ('/Admin'),
        ('/Compliance/Self Serve/Dublin'),
        ('/Directors/Daily Reports'),
        ('//Directors/Daily Reports/Monday/Tuesday')

UPDATE @CATALOG SET [Path] = REPLACE([Path], '//', '/') + @SEP -- At least one "/" at the end of the directory.

SELECT          
    SUBSTRING([Path], 2, CHARINDEX(@SEP, [Path], 2) -2)         AS Folder,
    SUBSTRING([Path], CHARINDEX(@SEP, [Path], 2) + 1, LEN([Path]) - IIF(LEN([Path]) > CHARINDEX(@SEP, [Path], 2) +1, CHARINDEX(@SEP, [Path], 2) +1, CHARINDEX(@SEP, [Path], 2) ) )  AS Subfolders
FROM @CATALOG