【问题标题】:Wrong Result in the CTE Hierarchical TreeCTE 层次树中的错误结果
【发布时间】:2017-04-04 17:47:03
【问题描述】:

我有这棵树

  • 国家
    • 地区
      • 城市
        • 协会
          • 中心
            • 学校

我这里有这个查询

;WITH MyCTE AS
(
  SELECT T1.ID, UserId,  NULL AS PARENT_ID, T1.GroupID, G.EntityLevelID
  FROM UserJobs T1
  INNER JOIN [GROUP] G ON T1.GROUPID = G.ID
  inner join EntityLevel el on G.EntityLevelID = el.Id 
  WHERE T1.UserID = 1

  UNION ALL

  SELECT T2.ID, T2.UserId,  EL.ParentID, T2.GroupID, G.EntityLevelID
  FROM UserJobs T2
  INNER JOIN [GROUP] G ON T2.GROUPID = G.ID
  inner join EntityLevel el on G.EntityLevelID = el.Id
  INNER JOIN MyCTE itms ON EL.ParentID >= itms.ID
)

SELECT B.*,  C.*, A.*
FROM (SELECT DISTINCT * FROM  MyCTE) A
INNER JOIN [USER] B ON A.UserID = B.ID
INNER JOIN [Group] C ON A.GroupID = C.ID
order by a.GroupID ;

如果我为 userID = 1 运行此查询

它会给我正确的数据(它会带来所有在 UserA = UserID = 1 下的用户)

1   UserA   1   Country Manager 1   1   1   NULL    1   1
2   UserB   2   Region Manager  2   2   2   1   2   2
8   UserH   2   Region Manager  2   8   8   1   2   2
3   UserC   3   City Manager    3   3   3   2   3   3
9   UserI   3   City Manager    3   9   9   2   3   3
4   UserD   4   Association Manager 4   4   4   3   4   4
10  UserJ   4   Association Manager 4   10  10  3   4   4
5   UserE   5   Center Manager  5   5   5   4   5   5
6   UserF   6   School Manager  6   6   6   5   6   6
7   UserG   7   Teacher 7   7   7   6   7   7

这实际上是我要找的,但是当我需要让UserI ID 等于 9 下的用户时,问题就来了

结果是:

9   UserI   3   City Manager    3   9   9   NULL    3   3

这是错误的,因为UserI 在他下面有一个用户UserJ

所以,结果一定是这样的

    9   UserI   3   City Manager    3   9   9   NULL    3   3
   10   UserJ   4   Association Manager 4   10  10  NULL    4   4

UserID = 3 中出现同样的错误,这给了我一个不在树中的 UserJ


脚本和数据在这里:

CREATE TABLE [dbo].[Assocation](
    [ID] [int] NOT NULL,
    [Name] [nvarchar](50) NULL,
    [CityID] [int] NULL,
 CONSTRAINT [PK_Assocation] PRIMARY KEY CLUSTERED 
(
    [ID] ASC
)WITH (PAD_INDEX = OFF, STATISTICS_NORECOMPUTE = OFF, IGNORE_DUP_KEY = OFF, ALLOW_ROW_LOCKS = ON, ALLOW_PAGE_LOCKS = ON) ON [PRIMARY]
) ON [PRIMARY]

GO
/****** Object:  Table [dbo].[Center]    Script Date: 2017-04-04 8:33:43 PM ******/
SET ANSI_NULLS ON
GO
SET QUOTED_IDENTIFIER ON
GO
CREATE TABLE [dbo].[Center](
    [ID] [int] NOT NULL,
    [Name] [nvarchar](50) NULL,
    [AssociationID] [int] NULL,
 CONSTRAINT [PK_Center] PRIMARY KEY CLUSTERED 
(
    [ID] ASC
)WITH (PAD_INDEX = OFF, STATISTICS_NORECOMPUTE = OFF, IGNORE_DUP_KEY = OFF, ALLOW_ROW_LOCKS = ON, ALLOW_PAGE_LOCKS = ON) ON [PRIMARY]
) ON [PRIMARY]

GO
/****** Object:  Table [dbo].[City]    Script Date: 2017-04-04 8:33:43 PM ******/
SET ANSI_NULLS ON
GO
SET QUOTED_IDENTIFIER ON
GO
CREATE TABLE [dbo].[City](
    [ID] [int] NOT NULL,
    [Name] [nvarchar](50) NULL,
    [RegionID] [int] NULL,
 CONSTRAINT [PK_City] PRIMARY KEY CLUSTERED 
(
    [ID] ASC
)WITH (PAD_INDEX = OFF, STATISTICS_NORECOMPUTE = OFF, IGNORE_DUP_KEY = OFF, ALLOW_ROW_LOCKS = ON, ALLOW_PAGE_LOCKS = ON) ON [PRIMARY]
) ON [PRIMARY]

GO
/****** Object:  Table [dbo].[Class]    Script Date: 2017-04-04 8:33:43 PM ******/
SET ANSI_NULLS ON
GO
SET QUOTED_IDENTIFIER ON
GO
CREATE TABLE [dbo].[Class](
    [ID] [int] NOT NULL,
    [Name] [nvarchar](50) NULL,
    [SchoolID] [int] NULL,
 CONSTRAINT [PK_Class] PRIMARY KEY CLUSTERED 
(
    [ID] ASC
)WITH (PAD_INDEX = OFF, STATISTICS_NORECOMPUTE = OFF, IGNORE_DUP_KEY = OFF, ALLOW_ROW_LOCKS = ON, ALLOW_PAGE_LOCKS = ON) ON [PRIMARY]
) ON [PRIMARY]

GO
/****** Object:  Table [dbo].[Country]    Script Date: 2017-04-04 8:33:43 PM ******/
SET ANSI_NULLS ON
GO
SET QUOTED_IDENTIFIER ON
GO
CREATE TABLE [dbo].[Country](
    [ID] [int] NOT NULL,
    [Name] [nvarchar](50) NULL,
 CONSTRAINT [PK_Country] PRIMARY KEY CLUSTERED 
(
    [ID] ASC
)WITH (PAD_INDEX = OFF, STATISTICS_NORECOMPUTE = OFF, IGNORE_DUP_KEY = OFF, ALLOW_ROW_LOCKS = ON, ALLOW_PAGE_LOCKS = ON) ON [PRIMARY]
) ON [PRIMARY]

GO
/****** Object:  Table [dbo].[EntityLevel]    Script Date: 2017-04-04 8:33:43 PM ******/
SET ANSI_NULLS ON
GO
SET QUOTED_IDENTIFIER ON
GO
CREATE TABLE [dbo].[EntityLevel](
    [ID] [int] NOT NULL,
    [Name] [nvarchar](50) NULL,
    [ParentID] [int] NULL,
 CONSTRAINT [PK_Table_1] PRIMARY KEY CLUSTERED 
(
    [ID] ASC
)WITH (PAD_INDEX = OFF, STATISTICS_NORECOMPUTE = OFF, IGNORE_DUP_KEY = OFF, ALLOW_ROW_LOCKS = ON, ALLOW_PAGE_LOCKS = ON) ON [PRIMARY]
) ON [PRIMARY]

GO
/****** Object:  Table [dbo].[Group]    Script Date: 2017-04-04 8:33:43 PM ******/
SET ANSI_NULLS ON
GO
SET QUOTED_IDENTIFIER ON
GO
CREATE TABLE [dbo].[Group](
    [ID] [int] NOT NULL,
    [Name] [nvarchar](50) NULL,
    [EntityLevelID] [int] NULL,
 CONSTRAINT [PK_Group] PRIMARY KEY CLUSTERED 
(
    [ID] ASC
)WITH (PAD_INDEX = OFF, STATISTICS_NORECOMPUTE = OFF, IGNORE_DUP_KEY = OFF, ALLOW_ROW_LOCKS = ON, ALLOW_PAGE_LOCKS = ON) ON [PRIMARY]
) ON [PRIMARY]

GO
/****** Object:  Table [dbo].[Region]    Script Date: 2017-04-04 8:33:43 PM ******/
SET ANSI_NULLS ON
GO
SET QUOTED_IDENTIFIER ON
GO
CREATE TABLE [dbo].[Region](
    [ID] [int] NOT NULL,
    [Name] [nvarchar](50) NULL,
    [CountryID] [int] NULL,
 CONSTRAINT [PK_Region] PRIMARY KEY CLUSTERED 
(
    [ID] ASC
)WITH (PAD_INDEX = OFF, STATISTICS_NORECOMPUTE = OFF, IGNORE_DUP_KEY = OFF, ALLOW_ROW_LOCKS = ON, ALLOW_PAGE_LOCKS = ON) ON [PRIMARY]
) ON [PRIMARY]

GO
/****** Object:  Table [dbo].[School]    Script Date: 2017-04-04 8:33:43 PM ******/
SET ANSI_NULLS ON
GO
SET QUOTED_IDENTIFIER ON
GO
CREATE TABLE [dbo].[School](
    [ID] [int] NOT NULL,
    [Name] [nvarchar](50) NULL,
    [CenterID] [int] NULL,
 CONSTRAINT [PK_School] PRIMARY KEY CLUSTERED 
(
    [ID] ASC
)WITH (PAD_INDEX = OFF, STATISTICS_NORECOMPUTE = OFF, IGNORE_DUP_KEY = OFF, ALLOW_ROW_LOCKS = ON, ALLOW_PAGE_LOCKS = ON) ON [PRIMARY]
) ON [PRIMARY]

GO
/****** Object:  Table [dbo].[User]    Script Date: 2017-04-04 8:33:43 PM ******/
SET ANSI_NULLS ON
GO
SET QUOTED_IDENTIFIER ON
GO
CREATE TABLE [dbo].[User](
    [ID] [int] NOT NULL,
    [Name] [nvarchar](50) NULL,
 CONSTRAINT [PK_User] PRIMARY KEY CLUSTERED 
(
    [ID] ASC
)WITH (PAD_INDEX = OFF, STATISTICS_NORECOMPUTE = OFF, IGNORE_DUP_KEY = OFF, ALLOW_ROW_LOCKS = ON, ALLOW_PAGE_LOCKS = ON) ON [PRIMARY]
) ON [PRIMARY]

GO
/****** Object:  Table [dbo].[UserJobs]    Script Date: 2017-04-04 8:33:43 PM ******/
SET ANSI_NULLS ON
GO
SET QUOTED_IDENTIFIER ON
GO
CREATE TABLE [dbo].[UserJobs](
    [ID] [int] NOT NULL,
    [UserID] [int] NOT NULL,
    [GroupID] [int] NOT NULL,
    [EntityID] [int] NOT NULL,
 CONSTRAINT [PK_UserJobs] PRIMARY KEY CLUSTERED 
(
    [ID] ASC,
    [UserID] ASC,
    [GroupID] ASC,
    [EntityID] ASC
)WITH (PAD_INDEX = OFF, STATISTICS_NORECOMPUTE = OFF, IGNORE_DUP_KEY = OFF, ALLOW_ROW_LOCKS = ON, ALLOW_PAGE_LOCKS = ON) ON [PRIMARY]
) ON [PRIMARY]

GO
INSERT [dbo].[Assocation] ([ID], [Name], [CityID]) VALUES (1, N'KH', 1)
GO
INSERT [dbo].[Assocation] ([ID], [Name], [CityID]) VALUES (2, N'mkh_ass', 2)
GO
INSERT [dbo].[Center] ([ID], [Name], [AssociationID]) VALUES (1, N'NorthCenter', 1)
GO
INSERT [dbo].[Center] ([ID], [Name], [AssociationID]) VALUES (2, N'SouthCenter', 1)
GO
INSERT [dbo].[City] ([ID], [Name], [RegionID]) VALUES (1, N'Jeddah', 1)
GO
INSERT [dbo].[City] ([ID], [Name], [RegionID]) VALUES (2, N'MakkahCiry', 1)
GO
INSERT [dbo].[Class] ([ID], [Name], [SchoolID]) VALUES (1, N'Class1', 1)
GO
INSERT [dbo].[Class] ([ID], [Name], [SchoolID]) VALUES (2, N'Class2', 1)
GO
INSERT [dbo].[Class] ([ID], [Name], [SchoolID]) VALUES (3, N'class3', 2)
GO
INSERT [dbo].[Class] ([ID], [Name], [SchoolID]) VALUES (4, N'class4', 2)
GO
INSERT [dbo].[Country] ([ID], [Name]) VALUES (1, N'KSA')
GO
INSERT [dbo].[Country] ([ID], [Name]) VALUES (2, N'UAE')
GO
INSERT [dbo].[EntityLevel] ([ID], [Name], [ParentID]) VALUES (1, N'Country', NULL)
GO
INSERT [dbo].[EntityLevel] ([ID], [Name], [ParentID]) VALUES (2, N'Region', 1)
GO
INSERT [dbo].[EntityLevel] ([ID], [Name], [ParentID]) VALUES (3, N'City', 2)
GO
INSERT [dbo].[EntityLevel] ([ID], [Name], [ParentID]) VALUES (4, N'Association', 3)
GO
INSERT [dbo].[EntityLevel] ([ID], [Name], [ParentID]) VALUES (5, N'Center', 4)
GO
INSERT [dbo].[EntityLevel] ([ID], [Name], [ParentID]) VALUES (6, N'School', 5)
GO
INSERT [dbo].[EntityLevel] ([ID], [Name], [ParentID]) VALUES (7, N'Class', 6)
GO
INSERT [dbo].[Group] ([ID], [Name], [EntityLevelID]) VALUES (1, N'Country Manager', 1)
GO
INSERT [dbo].[Group] ([ID], [Name], [EntityLevelID]) VALUES (2, N'Region Manager', 2)
GO
INSERT [dbo].[Group] ([ID], [Name], [EntityLevelID]) VALUES (3, N'City Manager', 3)
GO
INSERT [dbo].[Group] ([ID], [Name], [EntityLevelID]) VALUES (4, N'Association Manager', 4)
GO
INSERT [dbo].[Group] ([ID], [Name], [EntityLevelID]) VALUES (5, N'Center Manager', 5)
GO
INSERT [dbo].[Group] ([ID], [Name], [EntityLevelID]) VALUES (6, N'School Manager', 6)
GO
INSERT [dbo].[Group] ([ID], [Name], [EntityLevelID]) VALUES (7, N'Teacher', 7)
GO
INSERT [dbo].[Region] ([ID], [Name], [CountryID]) VALUES (1, N'Makkah', 1)
GO
INSERT [dbo].[Region] ([ID], [Name], [CountryID]) VALUES (2, N'Riyadh', 1)
GO
INSERT [dbo].[School] ([ID], [Name], [CenterID]) VALUES (1, N'School1', 1)
GO
INSERT [dbo].[School] ([ID], [Name], [CenterID]) VALUES (2, N'School2', 1)
GO
INSERT [dbo].[School] ([ID], [Name], [CenterID]) VALUES (3, N'School3', 2)
GO
INSERT [dbo].[User] ([ID], [Name]) VALUES (1, N'UserA')
GO
INSERT [dbo].[User] ([ID], [Name]) VALUES (2, N'UserB')
GO
INSERT [dbo].[User] ([ID], [Name]) VALUES (3, N'UserC')
GO
INSERT [dbo].[User] ([ID], [Name]) VALUES (4, N'UserD')
GO
INSERT [dbo].[User] ([ID], [Name]) VALUES (5, N'UserE')
GO
INSERT [dbo].[User] ([ID], [Name]) VALUES (6, N'UserF')
GO
INSERT [dbo].[User] ([ID], [Name]) VALUES (7, N'UserG')
GO
INSERT [dbo].[User] ([ID], [Name]) VALUES (8, N'UserH')
GO
INSERT [dbo].[User] ([ID], [Name]) VALUES (9, N'UserI')
GO
INSERT [dbo].[User] ([ID], [Name]) VALUES (10, N'UserJ')
GO
INSERT [dbo].[UserJobs] ([ID], [UserID], [GroupID], [EntityID]) VALUES (1, 1, 1, 1)
GO
INSERT [dbo].[UserJobs] ([ID], [UserID], [GroupID], [EntityID]) VALUES (2, 2, 2, 1)
GO
INSERT [dbo].[UserJobs] ([ID], [UserID], [GroupID], [EntityID]) VALUES (3, 3, 3, 1)
GO
INSERT [dbo].[UserJobs] ([ID], [UserID], [GroupID], [EntityID]) VALUES (4, 4, 4, 1)
GO
INSERT [dbo].[UserJobs] ([ID], [UserID], [GroupID], [EntityID]) VALUES (5, 5, 5, 1)
GO
INSERT [dbo].[UserJobs] ([ID], [UserID], [GroupID], [EntityID]) VALUES (6, 6, 6, 1)
GO
INSERT [dbo].[UserJobs] ([ID], [UserID], [GroupID], [EntityID]) VALUES (7, 7, 7, 1)
GO
INSERT [dbo].[UserJobs] ([ID], [UserID], [GroupID], [EntityID]) VALUES (8, 8, 2, 2)
GO
INSERT [dbo].[UserJobs] ([ID], [UserID], [GroupID], [EntityID]) VALUES (9, 9, 3, 2)
GO
INSERT [dbo].[UserJobs] ([ID], [UserID], [GroupID], [EntityID]) VALUES (10, 10, 4, 2)
GO

任何解决方案...

【问题讨论】:

  • 您的PARENT_ID 值不正确。具体来说,数据中的 UserJ 和 UserI 是如何关联的?哪个表和字段表明 UserJ 链接到 UserI 及其下方,或者 UserI 链接到 UserJ 及其上方?
  • @LaughingVergil 他们通过 UserJobs 和 Groups 关联在一起(正如您在 Group 中看到的 entityLevel)和 UserJ 进入 Association 下的 UserI City @级别

标签: sql-server tree common-table-expression hierarchical-data recursive-query


【解决方案1】:

我会重申您的PARENT_ID 值不正确。让我们详细查看 UserI (ID = 9) 查询以了解原因。

  SELECT T1.ID, UserId,  NULL AS PARENT_ID, T1.GroupID, G.EntityLevelID
  FROM #UserJobs T1
  INNER JOIN #GROUP G ON T1.GROUPID = G.ID
  inner join #EntityLevel el on G.EntityLevelID = el.Id 
  WHERE T1.UserID = 9

这将是处理 UserI 时的基本查询,如您的数据中定义的那样 (注意:我使用临时表而不是永久表来简化测试后的清理) 此查询片段的输出看起来像这样:

ID  UserId  PARENT_ID   GroupID EntityLevelID
9       9   NULL            3       3

目前没有问题。因此,您的 CTE 的递归部分是:

  UNION ALL

  SELECT T2.ID, T2.UserId,  EL.ParentID, T2.GroupID, G.EntityLevelID
  FROM #UserJobs T2
  INNER JOIN #GROUP G ON T2.GROUPID = G.ID
  inner join #EntityLevel el on G.EntityLevelID = el.Id
  INNER JOIN MyCTE itms 
      ON EL.ParentID >= itms.ID -- <<<< PROBLEM!!

正如我们在上面看到的,itms.ID 中该查询第一部分的值是 [9]。这需要连接到#EntityLevel.ParentID 字段中的值。但是,如果您查看插入到#EntityLevel 表中的值,您的最​​高ParentID 值是[6]。由于没有与itms.ID 值匹配的记录,因此没有链接其他记录。

UserID = 3 记录也有类似的问题(检查查询的输出以找出原因)。

回顾 - 如果您希望将一个项目链接到树中的另一个项目,则项目之间必须有一个特定的、唯一的链接。您需要确保存在特定的唯一链接。请注意,它不需要是单个数据值,但每次树分叉时,一个分支上的元素必须根据它们的数据值与另一分支上的元素明显不同。

【讨论】:

  • 谢谢你,但你认为我可以如何解决这个问题。如您所知,我需要使用此查询来查看特定用户下的每个用户,稍后我需要使用相同的查询从树中的特定点取出一棵树。
  • 你认为我可以在不同的表关系或消除一些未使用的表中实现我需要的东西
  • 在 SQL Server 中有几种不同的方式来表示树。最简单的方法是让您的父指针实际指向实际上是其父记录的记录 - 即用户级别的 parentID。另一种是将您的树表示为每个用户的数字范围 - 例如,使用上面显示的树,......好吧,用链接解释会更容易。参见维基百科的Nested Set Model。这是快速有效的,但不直观。一旦你弄清楚了,它是非常有效的。
  • 但我无法在User 级别中创建父级,因为它实际上是在实体级别上,如果我们在 `ON EL.ParentID >= itms.ID` 中添加一个 if 语句怎么样确保我们有另一个条件来检查女巫是Entity Level,实际上嵌套集模型在我的情况下不起作用
  • 当您说your PARENT_ID values are incorrect 时回到您的答案,我完全同意可以从多个关系中考虑父母。现在是这样吗,所以你看到真的UserIUserJ 无关,它们通过City 级别上的UserI 组和UserJAssociation 级别上相关
猜你喜欢
  • 2023-03-24
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2017-08-29
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多