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