获取SQL中父/子数据库中每个ID的相关数据

时间:2014-07-11 08:49:03

标签: sql-server tsql recursion common-table-expression

我使用下表

-- 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

您能帮助我获取每位用户及其所有权的所有相关代码吗?

2 个答案:

答案 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;