Sql server 从SQL Server中符号后的字符串到字段末尾(如果符号存在)的子字符串

Sql server 从SQL Server中符号后的字符串到字段末尾(如果符号存在)的子字符串,sql-server,string,uisplitviewcontroller,Sql Server,String,Uisplitviewcontroller,我查询了ReportServer数据库中的目录,以获取报表服务器中存在的文件夹列表。我得到的结果如下所示: [Path] /Admin /Compliance/Self Serve/Dublin /Directors/Daily Reports 所以一个顶级文件夹可以有一个正斜杠,两个顶级文件夹可以有两个正斜杠,一个底层可以有一个,而更深层的文件夹可以有3个或更多 我需要把它分成两部分。第一列应该是顶层文件夹名称,不带正斜杠,第二部分应该是下一层的文件夹结构的其余部分,例如 [Folder]

我查询了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;

我可以保证目录名的末尾有一个“/”字符,这样您就可以选择简单的解决方案(比如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

(1) 如果在查询实际表之前需要
更新
,那么这种方法是有缺陷的。(2) 建议的实现将因“…顶层文件夹的两个正向斜杠…”而失败。Oups!,谢谢(1) 您可以使用临时表进行转换。(2) 为“两个正向斜杠”添加了替换*(1)或用更新值替换SELECT查询中的[Path]。这太完美了,谢谢。这对我来说是一个新的学习层次(我以前没有做过任何像这样的XML查询),但我已经能够将其余的专栏都包含在其中,并使拆分工作完美地进行!
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