SQL - отдельный список иерархических меню - PullRequest
1 голос
/ 07 декабря 2011

Извините за большой пост. Я попытался упростить данные до основной проблемы. У меня есть 2 таблицы с большим количеством дублирующих данных, которые я пытаюсь оптимизировать / полностью реструктурировать. Я использую SQL Server 2008 R2

Menu * * 1004

[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  

Form1 и Form2 имеют одинаковую иерархию, но Form3 отличается (имеет Data2Filter2X)

Мне нужен SQL, который даст мне четкую иерархическую структуру меню.

Я имею в виду объединение таблиц RootMenu и Menu в 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 голосов
/ 12 декабря 2011

В этом ответе я использовал скрипт временной таблицы Эда Харпера. Моя первая и вторая попытка получить набор исключаемых строк не совсем верны. Вторая попытка намного длиннее, но результат тот же неправильный.

В конечном итоге, я думаю, что я хочу получить только парентидные 3 строки в таблице исключений, поскольку они являются дубликатами строк parentid1. Затем я могу исключить их из исходной таблицы меню. Я не хочу, чтобы 5 парентидных строк в таблице исключений, потому что строки меню отличаются от парентидных 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
0 голосов
/ 07 декабря 2011

Я не уверен, что полностью понял все правила системы, но кажется, что "рекурсивный" (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
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...