SQL - 不同的分层菜单列表

时间:2011-12-07 05:23:33

标签: sql-server-2008

对于大帖子感到抱歉。我试图将数据简化为核心问题。 我有2个表,有很多重复数据,我试图优化/完全重组。 我使用的是SQL Server 2008 R2

Menu

[Id] [int] IDENTITY(1,1) NOT NULL,
[ParentId] [int] NULL,
[Title] [varchar](50) NULL,
[ActionId] [int] NULL,
[Data] [varchar](500) NULL,
[FormId] [int] NULL,

RootMenu

[Id] [int] IDENTITY(1,1) NOT NULL,
[Name] [varchar](50) NULL,
[FormId] [int] NULL,

示例数据

Menu

Id  ParentId  Title   ActionId  Data           FormId
--  --------  ------  --------  -------------  ------
20  1         Title1  17        Data1Filter2   1
21  1         Title2  17        Data2Filter2   1
22  2         Title9  16        RootMenu2      1
23  2         Title5  17        Data3Filter2   1
24  3         Title1  17        Data1Filter2   2
25  3         Title2  17        Data2Filter2   2
26  4         Title9  16        RootMenu2      2
27  4         Title5  17        Data3Filter2   2
28  5         Title1  17        Data1Filter2   3
29  5         Title2  17        Data2Filter2X  3
30  6         Title9  16        RootMenu2      3
31  6         Title5  17        Data3Filter2   3

RootMenu

Id  Name       FormId
--  ---------  ------
1   RootMenu2  1
2   RootMenu3  1
3   RootMenu2  2
4   RootMenu3  2
5   RootMenu2  3
6   RootMenu3  3

此示例中有3个表单,菜单层次结构如下所示:

创建了菜单结构(Form1

RootMenu3              
  Title9                    -- as this action is 16 (recursive) it looks up RootMenu2 for Form 1, gets Id=1
    Title1  (Data1Filter2)  -- gets menu items with parentid =1
    Title2  (Data2Filter2)        
  Title5

创建了菜单结构(Form2

RootMenu3              
  Title9                    -- as this action is 16 (recursive) it looks up RootMenu2 for Form 2, gets Id=3
    Title1  (Data1Filter2)  -- gets menu items with parentid =3
    Title2  (Data2Filter2)        
  Title5  

创建了菜单结构(Form3

RootMenu3              
  Title9                    -- as this action is 16 (recursive) it looks up RootMenu2 for Form 3, gets Id=5
    Title1  (Data1Filter2)  -- gets menu items with parentid =5
    Title2  (Data2Filter2X)        
  Title5  

Form1Form2具有相同的层次结构,但Form3不同(有Data2Filter2X

我需要的是SQL,它将为我提供独特的分层菜单结构。

我正在考虑将RootMenuMenu表合并为1而不引用FormId,并创建FormMenu表:

CREATE TABLE [dbo].[FormMenu](
  [Id] [int] IDENTITY(1,1) NOT NULL,
  [FormId] [int] NOT NULL,
  [MenuId] [int] NOT NULL,
)

最终Menu数据

Id  ParentId  Title   ActionId  Data
--  --------  ------  --------  -------------
20  1         Title1  17        Data1Filter2
21  1         Title2  17        Data2Filter2
22  2         Title9  16        RootMenu2
23  2         Title5  17        Data3Filter2
28  5         Title1  17        Data1Filter2
29  5         Title2  17        Data2Filter2X
30  6         Title9  16        RootMenu2_v2
31  6         Title5  17        Data3Filter2

1  null RootMenu2     1 null  
2  null RootMenu3     1 null 
5  null RootMenu2_v2  3 null 
6  null RootMenu3_v2  3 null 

最终FormMenu数据

Id  FormId  MenuId
--  ------  ------
1   1       1    
2   1       2    
3   2       1    
4   2       2    
5   3       5    
6   3       6

如果您已经读过这篇文章,谢谢。你可以帮我用SQL来获得最终结果吗?

2 个答案:

答案 0 :(得分:0)

我不完全了解我已经完全理解了系统的所有规则,但似乎不需要“递归”(ActionId = 16条记录);只包含简单关系(ActionId = 17)的查询似乎产生了所需的输出:

测试数据:

DECLARE @menu TABLE
(
[Id] [INT] NOT NULL,
[ParentId] [INT] NULL,
[Title] [VARCHAR](50) NULL,
[ActionId] [INT] NULL,
[DATA] [VARCHAR](500) NULL,
[FormId] [INT] NULL
)

DECLARE @rootmenu TABLE
(
[Id] [INT] NOT NULL,
[Name] [VARCHAR](50) NULL,
[FormId] [INT] NULL
)

INSERT @menu (Id,ParentId,Title,ActionId,DATA,FormId)
      SELECT 20,1,'Title1',17,'Data1Filter2',1
UNION SELECT 21,1,'Title2',17,'Data2Filter2',1
UNION SELECT 22,2,'Title9',16,'RootMenu2',1
UNION SELECT 23,2,'Title5',17,'Data3Filter2',1
UNION SELECT 24,3,'Title1',17,'Data1Filter2',2
UNION SELECT 25,3,'Title2',17,'Data2Filter2',2
UNION SELECT 26,4,'Title9',16,'RootMenu2',2
UNION SELECT 27,4,'Title5',17,'Data3Filter2',2
UNION SELECT 28,5,'Title1',17,'Data1Filter2',3
UNION SELECT 29,5,'Title2',17,'Data2Filter2X',3
UNION SELECT 30,6,'Title9',16,'RootMenu2',3
UNION SELECT 31,6,'Title5',17,'Data3Filter2',3

INSERT @rootmenu (Id,Name,FormId)
SELECT 1,'RootMenu2',1
UNION SELECT 2,'RootMenu3',1
UNION SELECT 3,'RootMenu2',2
UNION SELECT 4,'RootMenu3',2
UNION SELECT 5,'RootMenu2',3
UNION SELECT 6,'RootMenu3',3

查询:

SELECT DISTINCT m.FormId, r.Id AS MenuId
FROM @menu AS m
JOIN @rootmenu AS r
ON r.Id = m.ParentId
WHERE m.ActionId = 17

答案 1 :(得分:0)

我在这个答案中使用了Ed Harper的临时表脚本。 我第一次和第二次尝试获取要排除的行是不太正确的。第二次尝试的时间要长得多,但结果却是错误的。

在最终结果中,我认为我只想在排除表中获得parentid 3行,因为它们是parentid1行的副本。 然后我可以将它们从原始菜单表中排除。 我不希望排除表中的parentid 5行,因为菜单行与parentid 1的菜单行不同

DECLARE @menu TABLE
(
[Id] [INT] NOT NULL,
[ParentId] [INT] NULL,
[Title] [VARCHAR](50) NULL,
[ActionId] [INT] NULL,
[DATA] [VARCHAR](500) NULL,
[FormId] [INT] NULL
)

DECLARE @rootmenu TABLE
(
[Id] [INT] NOT NULL,
[Name] [VARCHAR](50) NULL,
[FormId] [INT] NULL
)

INSERT @menu (Id,ParentId,Title,ActionId,DATA,FormId)
      SELECT 20,1,'Title1',17,'Data1Filter2',1
UNION SELECT 21,1,'Title2',17,'Data2Filter2',1
UNION SELECT 22,2,'Title9',16,'RootMenu2',1
UNION SELECT 23,2,'Title5',17,'Data3Filter2',1
UNION SELECT 24,3,'Title1',17,'Data1Filter2',2
UNION SELECT 25,3,'Title2',17,'Data2Filter2',2
UNION SELECT 26,4,'Title9',16,'RootMenu2',2
UNION SELECT 27,4,'Title5',17,'Data3Filter2',2
UNION SELECT 28,5,'Title1',17,'Data1Filter2',3
UNION SELECT 29,5,'Title2',17,'Data2Filter2X',3
UNION SELECT 30,6,'Title9',16,'RootMenu2',3
UNION SELECT 31,6,'Title5',17,'Data3Filter2',3

INSERT @rootmenu (Id,Name,FormId)
SELECT 1,'RootMenu2',1
UNION SELECT 2,'RootMenu3',1
UNION SELECT 3,'RootMenu3',2
UNION SELECT 4,'RootMenu3',2
UNION SELECT 5,'RootMenu3',3
UNION SELECT 6,'RootMenu3',4

--non recursive level 1 menu with Root
SELECT DISTINCT m.ParentId,m.Title,m.ActionId,m.DATA
FROM @menu AS m, @rootmenu AS r
where r.Id = m.ParentId
and m.ActionId<>16

--non recursive level 1 menu with Root
SELECT DISTINCT m.ParentId,m.Title,m.ActionId,m.DATA
FROM @menu AS m, @rootmenu AS r
where r.Id = m.ParentId
and m.ActionId=16

--level 1 menu without Root
--SELECT  m.ParentId,m.Title,m.ActionId,m.DATA
--FROM @menu AS m

--level 1 count
SELECT ParentId, COUNT(*) as count from
(
SELECT ParentId as ParentId,Title as Title,ActionId as ActionId,DATA as DATA
FROM @menu m3) as l1
 group by ParentId

 --2nd level menu
SELECT DISTINCT m2.ParentId,m2.Title,m2.ActionId,m2.DATA
FROM @menu AS m, @menu AS m2, @rootmenu AS r,@rootmenu AS r2
where r.Id = m.ParentId
and r2.Id = m2.ParentId
and m.DATA= r2.Name

--initial attempt at exclusion rows
select distinct Level1.* from
(SELECT DISTINCT m2.ParentId as ParentId,m2.Title as Title,m2.ActionId as ActionId,m2.DATA  as DATA
FROM @menu AS m, @menu AS m2, @rootmenu AS r,@rootmenu AS r2
where r.Id = m.ParentId
and r2.Id = m2.ParentId
and m.DATA= r2.Name) 
as Level2 ,
(SELECT DISTINCT ParentId as ParentId,Title as Title,ActionId as ActionId,DATA as DATA
FROM @menu
where ActionId<>16)
 as Level1 
where Level1.Title=Level2.Title 
and Level1.ActionId=Level2.ActionId 
and Level1.DATA=Level2.DATA 
and not Level1.ParentId=Level2.ParentId


 --second attempt at exclusion rows with Counts
select distinct Level1.* from
(SELECT DISTINCT m2.ParentId as ParentId,m2.Title as Title,m2.ActionId as ActionId,m2.DATA  as DATA
FROM @menu AS m, @menu AS m2, @rootmenu AS r,@rootmenu AS r2
where r.Id = m.ParentId
and r2.Id = m2.ParentId
and m.DATA= r2.Name) 
as Level2 
join
(SELECT ParentId, COUNT(*) as count from
(SELECT DISTINCT m2c.ParentId as ParentId,m2c.Title as Title,m2c.ActionId as ActionId,m2c.DATA  as DATA from
@menu AS mc, @menu AS m2c, @rootmenu AS rc,@rootmenu AS r2c
where rc.Id = mc.ParentId
and r2c.Id = m2c.ParentId
and mc.DATA= r2c.Name) as l2
Group by ParentId) as L2Count
 On  L2Count.ParentId= Level2.ParentId,

(SELECT DISTINCT ParentId as ParentId,Title as Title,ActionId as ActionId,DATA as DATA
FROM @menu
where ActionId<>16)
 as Level1 
 join

 (SELECT ParentId, COUNT(*) as count from
(
SELECT ParentId as ParentId,Title as Title,ActionId as ActionId,DATA as DATA
FROM @menu m3
where ActionId<>16) as l1
 group by ParentId) as L1Count
 On  L1Count.ParentId= Level1.ParentId

where Level1.Title=Level2.Title 
and Level1.ActionId=Level2.ActionId 
and Level1.DATA=Level2.DATA 
and not Level1.ParentId=Level2.ParentId
and L1Count.count= L2Count.count