CTE分层树中的错误结果

时间:2017-04-04 17:47:04

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

我是这棵树

  • 国家
    • 区域
        • 协会
          • 中心
            • 学校

enter image description here

我在这里有这个查询

;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

任何解决方案......

1 个答案:

答案 0 :(得分: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记录(检查查询的输出以找出原因)。

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