使用来自 2 个表的 JOIN 递归 SELECT

Recursive SELECT using JOIN from 2 tables

我有 2 个 table:用户角色

用户 table 列:

UserId  FirstName  Lastname

角色 table 列:

RoleId  UserId  ParentId

我希望能够从代表名为 ParentName.

的这 2 个 table 中获取日期

假设我有这些数据:

用户table:

UserId  FirstName  Lastname
1       John       Doe
2       Jane       Smith
3       John       Smith

角色table:

RoleId  UserId  ParentId
1       1       NULL
2       2       1
3       3       2

所以我想要这个 table:

UserId  FirstName  Lastname   RoleId   ParentId   ParentName 
1       John       Doe        1        NULL       NULL
2       Jane       Smith      2        1          John Doe
3       John       Smith      3        2          Jane Smith

我试过了,但我做不到。我尝试了 INNER JOIN、OUTER JOIN、子查询,但我无法得到我想要的。

将 2 个 table 连接在一起,我得到了这个:

SELECT UserId, FirstName, Lastname, RoleId, ParentId
FROM Users INNER JOIN Roles ON Users.UserId = Roles.UserId

并且加入一个自递归角色table我有这个:

SELECT ChildUsers.UserId, ChildUsers.RoleId, ParentUsers.UserId, ParentUsers.RoleId, Users.LastName
FROM Roles AS ChildUsers
LEFT JOIN Roles AS ParentUsers ON ChildUsers.ParentId = ParentUsers.RoleId 
INNER JOIN Users ON Users.UserId = ParentUsers.UserId

但是我得不到我想要的。我怎样才能得到它?

------------更新----------------

这是我自己的解决方案:

SELECT Roles.RoleID, LastName, Parent.ParentName FROM
Roles INNER JOIN Users ON Users.UserID = Roles.UserID LEFT JOIN
(SELECT LastName AS ParentName, RoleID FROM Users INNER JOIN Roles ON Users.UserID = Roles.UserID) Parent ON Parent.RoleID = Roles.ParentID

但我选择 LukStorms 解决方案作为答案。

试试这个查询:-

Create table Users (UserId INT, FirstName VARCHAR(255), LastName 
VARCHAR(255));
INSERT INTO Users VALUES(1,'John','Doe');
INSERT INTO Users VALUES(2,'Jane','Smith');
INSERT INTO Users VALUES(3,'John','Smith');

Create table Roles(RoleId INT, UserId INT, ParentId INT);
INSERT INTO ROles VALUES(1,1,NULL);
INSERT INTO ROles VALUES(2,2,1);
INSERT INTO ROles VALUES(3,3,2);

SELECT a.*,concat(b.FirstName,' ',b.Lastname) as ParentName
from 
(
SELECT a.UserId, FirstName, Lastname, RoleId, ParentId
FROM Users a INNER JOIN Roles b ON a.UserId = b.UserId
) a
left join
Users b
on a.ParentId=b.userid;

输出:-

    UserId  FirstName   Lastname    RoleId  ParentId    ParentName
1   1           John    Doe            1    NULL     
2   2           Jane    Smith          2    1            John Doe
3   3           John    Smith          3    2            Jane Smith

使用这个查询你可以得到你想要的结果。因为你只想要 2 级深度,你可以在没有递归查询的情况下做到这一点

DECLARE @Users TABLE (UserId INT, FirstName VARCHAR(255), LastName VARCHAR(255))
INSERT INTO @Users VALUES
(1,'John','Doe'),
(2,'Jane','Smith'),
(3,'John','Smith')

DECLARE @ROles TABLE (RoleId INT, UserId INT, ParentId INT)
INSERT INTO @ROles VALUES
(1,1,NULL),
(2,2,1),
(3,3,2)

SELECT  u.UserId, u.FirstName, u.LastName, r.RoleId, r.ParentId, p.ParentName
FROM    @Users AS u
    LEFT OUTER JOIN @Roles AS r ON r.UserId = u.UserId
    LEFT OUTER JOIN
        (SELECT r.UserId AS ParentId, up.FirstName + ' ' + up.LastName AS ParentName
         FROM   @ROles AS r 
            INNER JOIN
                @Users AS up ON up.UserId = r.ParentId) AS p ON p.ParentId = u.UserId

更新:添加结果

UserId  FirstName LastName  RoleId  ParentId ParentName
1       John      Doe       1       NULL     NULL
2       Jane      Smith     2       1        John Doe
3       John      Smith     3       2        Jane Smith

为了得到预期的结果?

如果 ParentId 包含 RoleId,那么这应该有效:

SELECT 
  r.UserId, 
  u.FirstName, 
  u.Lastname, 
  r.RoleId, 
  r.ParentId, 
  pu.FirstName+' '+pu.LastName AS ParentName 
FROM Roles r
LEFT JOIN Users u ON r.UserId = u.UserId
LEFT JOIN Roles pr on r.ParentId = pr.RoleId
LEFT JOIN Users pu on pr.UserId = pu.UserId

但是如果 ParentId 是用户的外键 table:

SELECT 
  r.UserId, 
  u.FirstName, 
  u.Lastname, 
  r.RoleId, 
  r.ParentId, 
  p.FirstName+' '+p.LastName AS ParentName
FROM Roles r
LEFT JOIN Users u ON r.UserId = u.UserId
LEFT JOIN Users p on r.ParentId = p.UserId

代码解释:

CTE 获取用户详细信息和角色。

LEFT JOINCTE 以获得 parent 的信息。将用户的 ParentId 与 Parents 的(也是用户)的 UserId 合并以获得 ParentName。

(注意:您可以 运行 单独的 cte 而不是第二个连接来查看输出。然后 运行 整体以查看它是如何连接的。)

CREATE TABLE [dbo].[Roles](
    [RoleId] [int] NULL,
    [UserId] [int] NULL,
    [ParentId] [int] NULL
)
;
CREATE TABLE [dbo].[Users](
    [UserId] [int] NULL,
    [FirstName] [varchar](20) NULL,
    [Lastname] [varchar](20) NULL
);



INSERT [dbo].[Roles] ([RoleId], [UserId], [ParentId]) VALUES (1, 1, NULL);
INSERT [dbo].[Roles] ([RoleId], [UserId], [ParentId]) VALUES (2, 2, 1);
INSERT [dbo].[Roles] ([RoleId], [UserId], [ParentId]) VALUES (3, 3, 2);

INSERT [dbo].[Users] ([UserId], [FirstName], [Lastname]) VALUES (1, N'John', N'Doe');
INSERT [dbo].[Users] ([UserId], [FirstName], [Lastname]) VALUES (2, N'Jane', N'Smith');
INSERT [dbo].[Users] ([UserId], [FirstName], [Lastname]) VALUES (3, N'John', N'Smith');


with cteUsers AS
(
    select u.UserId, u.FirstName, u.Lastname, r.RoleId, r.ParentId
    from Users AS u
    inner join Roles AS r
        on u.UserId=r.UserId
)
select 
     cteUsers.UserId
    ,cteUsers.FirstName 
    ,cteUsers.Lastname  
    ,cteUsers.RoleId    
    ,cteUsers.ParentId
    ,(p.FirstName + ' ' + p.Lastname) AS ParentName
from cteUsers
left join Users as p
    on cteUsers.ParentId=p.UserId
;

Run this script live