SQL 递归 CTE - 保留对父级的引用
SQL Recursive CTE - Keep reference to a parent
我有一个 table 具有以下结构
userId userName managerId
----------- ---------------- -----------
1 John NULL
2 Charles 1
3 Nicolas NULL
4 Neil 3
我还有另一个 table,其中包含以下内容
userId shareId
----------- -----------
1 1001
3 1002
所以我执行以下查询来获取我的递归 CTE:
WITH UserCTE AS (
SELECT userId, userName, managerId,0 AS steps
FROM dbo.Users
WHERE userId = 7
UNION ALL
SELECT mgr.userId, mgr.userName, mgr.managerId, usr.steps +1 AS steps
FROM UserCTE AS usr
INNER JOIN dbo.Users AS mgr
ON usr.managerId = mgr.userId
)
SELECT * FROM UserCTE AS u;
产生以下结果
userId userName managerId steps
----------- ---------------- ----------- -----------
1 John NULL 0
2 Charles 1 1
3 Nicolas NULL 0
4 Neil 3 1
好的,所以我想知道 shareId
拥有它的用户,以及属于他们的用户。
预期结果:
userId userName managerId steps shareId
----------- ---------------- ----------- ----------- ----------
1 John NULL 0 1001
2 Charles 1 1 1001
3 Nicolas NULL 0 1002
4 Neil 3 1 1002
有什么办法可以实现吗?
谢谢
在 Recursive CTE
的锚查询中加入 Share table
和 Users
table。试试这个。
;WITH UserCTE
AS (SELECT c.userId,
userName,
managerId,
0 AS steps,
shareId
FROM dbo.Users c
LEFT JOIN share_table s
ON c.userId = s.userId
WHERE managerId IS NULL
UNION ALL
SELECT mgr.userId,
mgr.userName,
mgr.managerId,
usr.steps + 1 AS steps,
usr.shareId
FROM UserCTE AS usr
INNER JOIN dbo.Users AS mgr
ON usr.userId = mgr.managerId)
SELECT *
FROM UserCTE AS u
ORDER BY userId;
你可以在 cte table 和 usershare table 上做 left join
。
WITH UserCTE AS (
SELECT userId, userName, managerId,0 AS steps
FROM dbo.Users
where managerId IS NULL
UNION ALL
SELECT mgr.userId, mgr.userName, mgr.managerId, usr.steps +1 AS steps
FROM UserCTE AS usr
INNER JOIN dbo.Users AS mgr
ON usr.userId = mgr.managerId
)
SELECT * FROM UserCTE AS u
left join userShare us
on u.managerId = us.userId
or u.userId = us.userId
order by u.userId
一种方法是在 UserCTE
table 和 share
table 之间的连接中使用 OR
。例如:
WITH UserCTE AS (
SELECT userId, userName, managerId,0 AS steps
FROM dbo.Users
WHERE userId = 7
UNION ALL
SELECT mgr.userId, mgr.userName, mgr.managerId, usr.steps +1 AS steps
FROM UserCTE AS usr
INNER JOIN dbo.Users AS mgr
ON usr.managerId = mgr.userId
)
SELECT * FROM UserCTE AS u
INNER JOIN [share table] AS s
ON u.userId = s.userId OR u.managerId s.userId;
但是,如果存在不止一级的管理层次结构,这可能会导致程序重复。 IE。经理也有经理。另一种方法是在 UserCTE
table 的 userId
列上创建两个左连接,一个连接到 share
table,另一个连接到 managerId
UserCTE
table 到 share
table 的列。然后,您可以在 shareId
列上使用 CASE
语句来决定您需要哪一个。见下文:
WITH UserCTE AS (
SELECT userId, userName, managerId,0 AS steps
FROM dbo.Users
WHERE userId = 7
UNION ALL
SELECT mgr.userId, mgr.userName, mgr.managerId, usr.steps +1 AS steps
FROM UserCTE AS usr
INNER JOIN dbo.Users AS mgr
ON usr.managerId = mgr.userId
)
SELECT
u.*
,CASE
WHEN su.shareId is not null THEN su.shareId
WHEN sm.shareId is not null THEN sm.shareId
ELSE null END as shareID
FROM UserCTE AS u
LEFT JOIN [share table] AS su
ON u.userId = s.userId
LEFT JOIN [share table] AS sm
ON u.managerId = s.userId;
希望对您有所帮助。
我有一个 table 具有以下结构
userId userName managerId
----------- ---------------- -----------
1 John NULL
2 Charles 1
3 Nicolas NULL
4 Neil 3
我还有另一个 table,其中包含以下内容
userId shareId
----------- -----------
1 1001
3 1002
所以我执行以下查询来获取我的递归 CTE:
WITH UserCTE AS (
SELECT userId, userName, managerId,0 AS steps
FROM dbo.Users
WHERE userId = 7
UNION ALL
SELECT mgr.userId, mgr.userName, mgr.managerId, usr.steps +1 AS steps
FROM UserCTE AS usr
INNER JOIN dbo.Users AS mgr
ON usr.managerId = mgr.userId
)
SELECT * FROM UserCTE AS u;
产生以下结果
userId userName managerId steps
----------- ---------------- ----------- -----------
1 John NULL 0
2 Charles 1 1
3 Nicolas NULL 0
4 Neil 3 1
好的,所以我想知道 shareId
拥有它的用户,以及属于他们的用户。
预期结果:
userId userName managerId steps shareId
----------- ---------------- ----------- ----------- ----------
1 John NULL 0 1001
2 Charles 1 1 1001
3 Nicolas NULL 0 1002
4 Neil 3 1 1002
有什么办法可以实现吗?
谢谢
在 Recursive CTE
的锚查询中加入 Share table
和 Users
table。试试这个。
;WITH UserCTE
AS (SELECT c.userId,
userName,
managerId,
0 AS steps,
shareId
FROM dbo.Users c
LEFT JOIN share_table s
ON c.userId = s.userId
WHERE managerId IS NULL
UNION ALL
SELECT mgr.userId,
mgr.userName,
mgr.managerId,
usr.steps + 1 AS steps,
usr.shareId
FROM UserCTE AS usr
INNER JOIN dbo.Users AS mgr
ON usr.userId = mgr.managerId)
SELECT *
FROM UserCTE AS u
ORDER BY userId;
你可以在 cte table 和 usershare table 上做 left join
。
WITH UserCTE AS (
SELECT userId, userName, managerId,0 AS steps
FROM dbo.Users
where managerId IS NULL
UNION ALL
SELECT mgr.userId, mgr.userName, mgr.managerId, usr.steps +1 AS steps
FROM UserCTE AS usr
INNER JOIN dbo.Users AS mgr
ON usr.userId = mgr.managerId
)
SELECT * FROM UserCTE AS u
left join userShare us
on u.managerId = us.userId
or u.userId = us.userId
order by u.userId
一种方法是在 UserCTE
table 和 share
table 之间的连接中使用 OR
。例如:
WITH UserCTE AS (
SELECT userId, userName, managerId,0 AS steps
FROM dbo.Users
WHERE userId = 7
UNION ALL
SELECT mgr.userId, mgr.userName, mgr.managerId, usr.steps +1 AS steps
FROM UserCTE AS usr
INNER JOIN dbo.Users AS mgr
ON usr.managerId = mgr.userId
)
SELECT * FROM UserCTE AS u
INNER JOIN [share table] AS s
ON u.userId = s.userId OR u.managerId s.userId;
但是,如果存在不止一级的管理层次结构,这可能会导致程序重复。 IE。经理也有经理。另一种方法是在 UserCTE
table 的 userId
列上创建两个左连接,一个连接到 share
table,另一个连接到 managerId
UserCTE
table 到 share
table 的列。然后,您可以在 shareId
列上使用 CASE
语句来决定您需要哪一个。见下文:
WITH UserCTE AS (
SELECT userId, userName, managerId,0 AS steps
FROM dbo.Users
WHERE userId = 7
UNION ALL
SELECT mgr.userId, mgr.userName, mgr.managerId, usr.steps +1 AS steps
FROM UserCTE AS usr
INNER JOIN dbo.Users AS mgr
ON usr.managerId = mgr.userId
)
SELECT
u.*
,CASE
WHEN su.shareId is not null THEN su.shareId
WHEN sm.shareId is not null THEN sm.shareId
ELSE null END as shareID
FROM UserCTE AS u
LEFT JOIN [share table] AS su
ON u.userId = s.userId
LEFT JOIN [share table] AS sm
ON u.managerId = s.userId;
希望对您有所帮助。