我使用下表
-- USER TABLE --
User_ID | Manager_ID | Code
1 | null | ABC
2 | 1 | DEF
3 | 2 | HIJ
4 | null | ABC
我需要知道与每个用户相关的代码以及代码是否“拥有”。当代码在同一行时,用户“拥有”相关代码
User_ID = 1 :拥有代码= ABC
但我还需要通过层次结构Manager_ID知道与每个用户相关的代码 - >用户身份。此层次结构没有最大深度。
User_ID = 1 :相关代码= DEF (通过User_ID 2)和 HIJ (通过User_ID 3)
在我的例子中,我想得到以下结果
User_ID | Code | IsOwner
1 | ABC | 1
1 | DEF | 0
1 | HIJ | 0
2 | DEF | 1
2 | HIJ | 0
3 | HIJ | 1
4 | ABC | 1
对于拥有的代码,很简单,我做了以下查询:
SELECT User_ID, Code, 1 as IsOwner
FROM User
但我遇到了层次结构的一些问题。我试图在互联网上找到示例,但我只看到“级别”或“计数”的请求,我不知道如何检索所有相关代码。
我看到Common Table Expression并尝试了类似的查询,但我想我错过了一些东西......
USE MyBD
GO
WITH MyCTE (Manager_ID, User_ID, Code, IsOwned)
AS
(
SELECT Manager_ID, User_ID, Code, 1 as IsOwned
FROM User
WHERE Manager_ID IS NULL
UNION ALL
SELECT u.Manager_ID, u.User_ID, u.Code, 1 as IsOwned
FROM User AS u
INNER JOIN Managers AS d
ON u.Manager_ID = d.User_ID
)
SELECT Manager_ID, User_ID, Code, IsOwned
FROM Managers
GO
您能帮助我获取每位用户及其所有权的所有相关代码吗?
答案 0 :(得分:2)
我找到的唯一方法,最后是用串联保留层次结构的跟踪,然后拆分连接值。
WITH Managers
AS
(
SELECT Manager_ID, User_ID, Code, cast(User_ID as varchar(max)) as hierarchy
FROM Users
WHERE Manager_ID IS NULL
UNION ALL
SELECT u.Manager_ID, u.User_ID, u.Code, d.hierarchy + case when d.hierarchy <> '' then '_' else '' end + cast(u.user_id as varchar)
FROM Users AS u
INNER JOIN Managers AS d
ON u.Manager_ID = d.User_ID
)
SELECT splitdata, Code, case when splitdata = user_id then 1 else 0 end as IsOwner
FROM
(
SELECT *,
-- this part, for readability, should be replace by a split function
cast('<X>'+replace(F.hierarchy,'_','</X><X>')+'</X>' as XML) as xmlfilter from Managers F
)a
CROSS APPLY
(
SELECT cast(fdata.D.value('.','varchar(50)') as int) as splitdata
FROM a.xmlfilter.nodes('X') as fdata(D)) s
order by splitdata, Code
请参阅sqlfiddle。
sqlfiddle也只有CTE结果的一部分,以帮助理解。
修改强>
由于可能存在误解(关于什么是所有者),这里是以前的版本,由Tom Chantler进行更正!
WITH Managers
AS
(
SELECT Manager_ID, User_ID, user_ID as topManager, Code
FROM Users
WHERE Manager_ID IS NULL
UNION ALL
SELECT u.Manager_ID, u.User_ID, d.topManager as topManager, u.Code
FROM Users AS u
INNER JOIN Managers AS d
ON u.Manager_ID = d.User_ID
)
select topManager, Code, 0 from Managers
where manager_ID is not null
union
select user_ID, Code, CASE WHEN topManager = User_Id THEN 1 ELSE 0 END from Managers
union
select Manager_ID, Code, 0 from Managers
where Manager_ID is not null;
答案 1 :(得分:1)
我对您的查询进行了一些小修改。请尝试以下操作:我删除了第一个查询中的where条件,因为您需要为所有用户(而不仅仅是管理员)获取层次结构。并且还改变了连接条件
;WITH MyCTE (Manager_ID, User_ID, Code, IsOwned)
AS
(
SELECT User_ID, User_ID, Code, 1 as IsOwned
FROM [User]
UNION ALL
SELECT d.Manager_ID, u.User_ID, u.Code, 0 as IsOwned
FROM [User] AS u
INNER JOIN MyCTE AS d
ON u.Manager_ID = d.User_ID
)
SELECT Manager_ID, User_ID, Code, IsOwned
FROM MyCTE ORDER BY Manager_ID,Code;