'Recursive CTE check if record exists at any level then get all children (folder structure)
I'm trying to check using a recursive CTE if a user has access to a folder and if they do, then the folder and all children
The structure is basic
CREATE TABLE [dbo].[Folders](
[Id] [int] IDENTITY(1,1) NOT NULL,
[Name] [nvarchar](1024) NOT NULL,
[ParentId] [int] NULL)
This is the table that links a user to a folder
CREATE TABLE [dbo].[FolderAccess](
[Id] [int] IDENTITY(1,1) NOT NULL,
[UserId] [bigint] NOT NULL,
[FolderId] [int] NOT NULL)
Using the following example data
SELECT * FROM Folders
| Id | ParentId | Name |
|---|---|---|
| 1 | NULL | Root |
| 2 | 1 | Sub folder 1 |
| 3 | 2 | Sub folder 2 |
| 4 | 3 | Sub folder 3 |
| 5 | 4 | Sub folder 4 |
| 6 | 5 | Sub folder 5 |
SELECT UserId, FolderId FROM FolderAccess
| UserId | FolderId |
|---|---|
| 1 | 3 |
The user above has access to folder 3 so indirectly has access to folder 4,5,6
I should be able to put any FolderId 3,4,5,6 and get results but using folder id 2 would return nothing as that is higher up the hierarchy.
DECLARE @FolderId INT = 3
;WITH TopDownFolderHierarchy (Id, ParentId , Name)
AS
(
SELECT fold.Id, fold.ParentId, fold.Name FROM Folders fold
WHERE fold.ID = @FolderId
UNION ALL
SELECT parents.Id, parents.ParentId, parents.Name FROM Folders parents
INNER JOIN TopDownFolderHierarchy cte on cte.Id = parents.ParentId
)
Thanks
Solution 1:[1]
The query below tries first to list folders the user has access to then the required hierarchy among accessible folders
DECLARE @UserId INT = 1;
DECLARE @FolderId INT = 5;
WITH
AccessibleHierarchy (Id, ParentId , Name) AS
(
SELECT fold.Id, fold.ParentId, fold.Name FROM Folders fold
WHERE fold.[CreatorUserId] = @UserId or fold.ID in (select [FolderId] from [FolderAccess] where [UserId] = @UserId)
UNION ALL
SELECT parents.Id, parents.ParentId, parents.Name FROM Folders parents
INNER JOIN AccessibleHierarchy cte on cte.Id = parents.ParentId
),
QueriedHierarchy (Id, ParentId , Name) AS
(
SELECT distinct fold.Id, fold.ParentId, fold.Name FROM AccessibleHierarchy fold
WHERE fold.ID = @FolderId
UNION ALL
SELECT parents.Id, parents.ParentId, parents.Name FROM Folders parents
INNER JOIN QueriedHierarchy cte on cte.Id = parents.ParentId
)
select * from QueriedHierarchy
edit: added use of a CreatorUserId column in Folders and added a distinct keyword in QueriedHierarchy in case there a hierarchy is allowed by multiple CreatorUserId/FolderAccess
Sources
This article follows the attribution requirements of Stack Overflow and is licensed under CC BY-SA 3.0.
Source: Stack Overflow
| Solution | Source |
|---|---|
| Solution 1 |
