傳統無限級分類表僅含 Id, ParentId, Name 三欄,查詢某節點所有子孫需遞迴或多次查詢,效能低且程式複雜。解決方案:新增路徑欄位,記錄從根節點到當前節點的完整路徑,查詢子孫變為簡單的 LIKE 'path/%' 操作。
CREATE TABLE [Sort] (
[Id] INT PRIMARY KEY,
[ParentId] INT NULL,
[Name] NVARCHAR(500),
[IdPath] VARCHAR(500), -- 如 '/1/3/7/'
[NamePath] NVARCHAR(500) -- 如 '/根目錄/子目錄/孫目錄/'
);
建立 SetSortPath 存儲過程,接受 @Id 參數,向上遞迴父節點構建路徑:
CREATE PROCEDURE [dbo].[SetSortPath]
@Id INT
AS
BEGIN
SET NOCOUNT ON;
DECLARE @PId VARCHAR(10), @ParentId INT, @Name NVARCHAR(500);
DECLARE @IdPath VARCHAR(500) = '/', @NamePath NVARCHAR(500) = '/';
SELECT @PId = [ParentId] FROM [Sort] WHERE [Id] = @Id;
WHILE (@PId IS NOT NULL)
BEGIN
SELECT @ParentId = [ParentId], @Name = [Name] FROM [Sort] WHERE [Id] = @PId;
SET @IdPath = '/' + @PId + @IdPath;
SET @NamePath = '/' + @Name + @NamePath;
IF (@ParentId <> @PId) SET @PId = @ParentId;
ELSE SET @PId = NULL; -- 防止循環引用
END
IF (@IdPath = '/')
UPDATE [Sort] SET [IdPath] = NULL, [NamePath] = NULL WHERE [Id] = @Id;
ELSE
UPDATE [Sort] SET [IdPath] = @IdPath, [NamePath] = @NamePath WHERE [Id] = @Id;
END
在 Sort 表上建立 INSERT, UPDATE, DELETE 觸發器,呼叫 SetSortPath:
-- 取得 Id=3 節點的所有子孫
SELECT * FROM [Sort] WHERE [IdPath] LIKE '/3/%';
-- 取得完整路徑顯示
SELECT [NamePath] FROM [Sort] WHERE [Id] = 7;
-- 結果: /根目錄/子目錄/孫目錄/
| 優點 | 缺點 |
|---|---|
| 查詢子孫極快,無需遞迴 | 修改節點需更新所有後代路徑,寫入開銷大 |
| 路徑資訊直觀,易於報表顯示 | 路徑長度有限制,極深層級可能截斷 |
| 支援名稱路徑與 ID 路徑雙重查詢 | 需透過觸發器/存儲過程確保資料一致性 |
路徑枚舉模式適合「讀多寫少」的分類場景。若寫入頻繁,可考慮 Closure Table(關係閉包表)或遞迴 CTE 方案。