0

如何创建解析文件夹路径并返回表的函数?

分隔符将是反斜杠\。输入将是一个文件夹路径 FolderA\FolderB

输出将是一个按顺序包含文件夹的表格:

FolderName: FolderA  FolderB    
Level:      0      1
4

1 回答 1

4

这个问题可以推广到字符串拆分问题。T-SQL 中的字符串操作是可能的,但难以理解,因为复杂表达式的语法笨拙。

Itzik Ben-Gan 在他对sqlservercode博客的采访中提供了解决此问题所需的所有技巧。

字符串分割函数

Itzik 提供了一个用于拆分字符串的内联表值函数,通过一些修改,它将解决您的问题:

CREATE FUNCTION dbo.fn_split(@arr AS VARCHAR(MAX)) RETURNS TABLE
AS
RETURN
  SELECT
    n - LEN(REPLACE(LEFT(@arr, n), ',', '')) + 1 AS pos,
    SUBSTRING(@arr, n,
      CHARINDEX(',', @arr + ',', n) - n) AS element
  FROM dbo.Nums
  WHERE n <= LEN(@arr) AND SUBSTRING(',' + @arr, n, 1) = ',';  

此功能允许您将逗号分隔的元素字符串拆分为位置索引表。像这样的查询:

SELECT * FROM dbo.fn_split('10248,10249,10250'); 

生成如下结果集:

pos element
---- --------
1 10248
2 10249
3 10250

一个辅助数字表

字符串拆分功能依赖于辅助数字表。您的数据库中可能已经有其中之一,因为它们对于解决各种问题很有用。

如果您没有,您可以调整 Itzik 推荐的另一个内联表值函数,以提高效率,如果不是清晰的话:

CREATE FUNCTION dbo.fn_nums(@n AS BIGINT) RETURNS TABLE
AS
RETURN
  WITH
  L0   AS(SELECT 1 AS c UNION ALL SELECT 1),
  L1   AS(SELECT 1 AS c FROM L0 AS A, L0 AS B),
  L2   AS(SELECT 1 AS c FROM L1 AS A, L1 AS B),
  L3   AS(SELECT 1 AS c FROM L2 AS A, L2 AS B),
  L4   AS(SELECT 1 AS c FROM L3 AS A, L3 AS B),
  L5   AS(SELECT 1 AS c FROM L4 AS A, L4 AS B),
  Nums AS(SELECT ROW_NUMBER() OVER(ORDER BY c) AS n FROM L5)
  SELECT n FROM Nums 
  WHERE n <= @n;  

此函数允许您生成具有指定行数的表。像这样的查询:

SELECT * FROM dbo.fn_nums(10);  

生成如下结果集:

n
---
1
2
3
4
5
6
7
8
9
10

一个通用的自包含字符串拆分函数

通过组合字符串拆分器和行生成器,您可以使函数自包含,我的意思是它独立于数据库中的其他对象工作。

通过添加一个指定分隔符的额外参数,您可以使字符串拆分器通用,因为它将拆分由任何字符分隔的字符串,而不仅仅是逗号。

您可以将 Itzik 的 string'splitter 替换为修改后的版本,如下所示:

CREATE FUNCTION dbo.fn_split(@arr AS VARCHAR(MAX), @delim AS CHAR(1)) RETURNS TABLE
AS
RETURN
  WITH
  L0   AS(SELECT 1 AS c UNION ALL SELECT 1),
  L1   AS(SELECT 1 AS c FROM L0 AS A, L0 AS B),
  L2   AS(SELECT 1 AS c FROM L1 AS A, L1 AS B),
  L3   AS(SELECT 1 AS c FROM L2 AS A, L2 AS B),
  L4   AS(SELECT 1 AS c FROM L3 AS A, L3 AS B),
  L5   AS(SELECT 1 AS c FROM L4 AS A, L4 AS B),
  Nums AS(SELECT ROW_NUMBER() OVER(ORDER BY c) AS n FROM L5)
  SELECT
    n - LEN(REPLACE(LEFT(@arr, n), @delim, '')) + 1 AS pos,
    SUBSTRING(@arr, n,
      CHARINDEX(@delim, @arr + @delim, n) - n) AS element
  FROM Nums
  WHERE n <= LEN(@arr) AND SUBSTRING(@delim + @arr, n, 1) = @delim;

您可以通过传递与以前相同的参数并传递逗号作为分隔符来复制原始函数的输出:

SELECT * FROM dbo.fn_split('10248,10249,10250', ',');

它产生如下结果集:

POS ELEMENT
1   10248
2   10249
3   10250

解决您的问题

现在我们有了一个可以为任何分隔的元素字符串生成表格的函数,我们可以解决您的问题。

使用通用的自包含字符串拆分器,您可以使用以下查询:

SELECT
  Element AS FolderName,
  Pos - 1 AS Level
FROM dbo.fn_split('FolderA\FolderB', '\');

它产生如下结果集:

FOLDERNAME  LEVEL
FolderA 0
FolderB 1

SQL Server 对字符串操作和由 ROW_NUMBER 函数生成的序列等序列使用从 1 开始的索引,因此通用字符串拆分器应遵循此约定是有意义的。

因为您希望路径中的第一个文件夹为 0 级,所以查询从元素位置减去 1 以获得从 0 开始的索引。

您可以在SQL Fiddle上使用此解决方案进行实验。

于 2012-09-30T12:48:15.323 回答