【问题标题】:Get data related for each ID in a parent/child Database in tSQL在 SQL 中获取父/子数据库中每个 ID 的相关数据
【发布时间】:2014-07-11 08:49:02
【问题描述】:

我使用下表

-- 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 了解每个用户的相关代码。此层次结构没有最大深度。

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

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

【问题讨论】:

  • 你有一个最大的层次深度,或者没有?
  • @RaphaëlAlthaus 不,我没有最大深度,我编辑我的帖子

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


【解决方案1】:

最后,我发现的唯一方法是通过串联保留层次结构的痕迹,然后拆分串联的值。

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;

【讨论】:

  • 这很棒。我正在做类似的事情,但我认为这更好。
  • @TomChantler 嗯,遗憾的是,如果层次结构的深度有更多级别,我认为某些级别将不会返回......
  • 检查一下:sqlfiddle.com/#!6/a1e242/4 我添加了一些额外的层次结构,这不像你说的那样工作,但后来我将新的“所有者”列从 1 更改为 CASE WHEN topManager = User_Id THEN 1 ELSE 0 END 所以它只显示用户是否是最高管理者。它有效,也许你可以更新你的答案?
  • @TomChantler 认为它仍然不完全是这样(例如,没有 NOP,IsOwner = 1),但我想我现在明白了。我把我的新结果和你的结果放在一起,你可以看到一些不同。顺便说一句,很好的挑战;)sqlfiddle.com/#!6/a1e242/12
  • NOP 不应该有 IsOwner = 1,因为它实际上只由 User_id 1 拥有。我的意思是,根据我对问题。根据您的理解,您的显然是正确的。但我确实喜欢你的东西,这很酷:-)
【解决方案2】:

我对您的查询做了一些小的修改。尝试以下操作:我删除了第一个查询中的 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;

【讨论】:

  • 感谢您的回答,我尝试了您的查询并进行了一些更改。我可以得到层次结构,但只能从下到上......在我的例子中,我得到(3,HIJ,1)(3,DEF,0)和(3,ABC,0)。我感觉如此接近,但在理解这些 CTE 时遇到了一些困难。
猜你喜欢
  • 2015-07-25
  • 1970-01-01
  • 2010-10-05
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2017-12-28
  • 2020-04-11
相关资源
最近更新 更多