Уплощение таблицы, содержащей строки, ссылающиеся на другие строки в SQL Server 2005 - PullRequest
3 голосов
/ 26 мая 2010

Я сталкиваюсь с проблемой, которая иногда возникает, когда вы имеете дело с не полностью нормализованной таблицей. Здесь проблема. Представьте себе таблицу с 4 столбцами, и давайте назовем эту таблицу dbo.Hierarchical. Вот определение таблицы:

if OBJECT_ID('dbo.Hierarchical') is not null
 drop table dbo.Hierarchical

create table dbo.Hierarchical
(
  colID   int   not null identity(1,1) primary key
 ,GroupName  varchar(5) not null
 ,IsAtomic  bit   not null
 ,Constituent varchar(5) null
)

Эта таблица может иметь GroupName, то есть Atomic, что означает, что она не имеет компонента или не может быть Atomic. В этом случае GroupName может содержать другие GroupNames.

Для наглядности заполните таблицу некоторыми данными.

set nocount on
insert into dbo.Hierarchical values ('A',0,'B')
insert into dbo.Hierarchical values ('A',0,'C')
insert into dbo.Hierarchical values ('B',1,'B')
insert into dbo.Hierarchical values ('C',0,'K')
insert into dbo.Hierarchical values ('C',0,'L')
insert into dbo.Hierarchical values ('D',0,'E')
insert into dbo.Hierarchical values ('D',0,'F')
insert into dbo.Hierarchical values ('D',0,'G')
insert into dbo.Hierarchical values ('E',1,'E')
insert into dbo.Hierarchical values ('F',1,'F')
insert into dbo.Hierarchical values ('G',0,'H')
insert into dbo.Hierarchical values ('G',0,'I')
insert into dbo.Hierarchical values ('H',1,'H')
insert into dbo.Hierarchical values ('I',1,'I')
insert into dbo.Hierarchical values ('J',1,'J')
insert into dbo.Hierarchical values ('K',1,'K')
insert into dbo.Hierarchical values ('L',1,'L')
insert into dbo.Hierarchical values ('M',1,'M')
insert into dbo.Hierarchical values ('N',1,'N')
set nocount off

Теперь, если мы посмотрим на простой выбор * из dbo.Hierarchical, мы получим следующее:

GroupName  colID      IsAtomic   Constituent
A           1         0          B
A           2         0          C
B           3         1          B
C           4         0          K
C           5         0          L
D           6         0          E
D           7         0          F
D           8         0          G
E           9         1          E
F          10         1          F
G          11         0          H
G          12         0          I
H          13         1          H
I          14         1          I
J          15         1          J
K          16         1          K
L          17         1          L
M          18         1          M
N          19         1          N

Уфф, это было долго наматываться. Теперь обратите внимание, что первые две строки имеют GroupName A и Contiuents B и C. B является атомарным, поэтому у него нет дополнительных компонентов. C, однако, имеет константы K, L (K и L являются атомными). Как я могу создать представление, которое сгладит эту таблицу, чтобы я мог видеть только GroupName и Atomic Contiuents. В случае GroupName A я должен увидеть 3 строки

A B
A K
A L

Ответы [ 3 ]

4 голосов
/ 26 мая 2010

Попробуйте:

--just a repeat of OP's original table and data
DECLARE @Hierarchical table
( colID   int   not null identity(1,1) primary key
 ,GroupName  varchar(5) not null
 ,IsAtomic  bit   not null
 ,Constituent varchar(5) null)
set nocount on
insert into @Hierarchical values ('A',0,'B');insert into @Hierarchical values ('A',0,'C');
insert into @Hierarchical values ('B',1,'B');insert into @Hierarchical values ('C',0,'K');
insert into @Hierarchical values ('C',0,'L');insert into @Hierarchical values ('D',0,'E');
insert into @Hierarchical values ('D',0,'F');insert into @Hierarchical values ('D',0,'G');
insert into @Hierarchical values ('E',1,'E');insert into @Hierarchical values ('F',1,'F');
insert into @Hierarchical values ('G',0,'H');insert into @Hierarchical values ('G',0,'I');
insert into @Hierarchical values ('H',1,'H');insert into @Hierarchical values ('I',1,'I');
insert into @Hierarchical values ('J',1,'J');insert into @Hierarchical values ('K',1,'K');
insert into @Hierarchical values ('L',1,'L');insert into @Hierarchical values ('M',1,'M');
insert into @Hierarchical values ('N',1,'N');set nocount off

--declare and set starting position
DECLARE @Start  varchar(5)
SET @Start='A'

--get the data
;WITH HierarchicalTree AS
(
    SELECT 
        GroupName, Constituent,  1 AS LevelOf
        FROM @Hierarchical
        WHERE GroupName=@Start
    UNION ALL
        SELECT 
            t.GroupName, h.Constituent, t.LevelOf+1
        FROM HierarchicalTree         t
            INNER JOIN @Hierarchical  h ON t.Constituent=h.GroupName
        WHERE h.Constituent!=h.GroupName AND h.IsAtomic=0
)
SELECT
    t.GroupName,t.Constituent
    FROM HierarchicalTree        t
        INNER JOIN @Hierarchical h ON t.Constituent=h.GroupName
    WHERE h.IsAtomic=1

ВЫХОД:

GroupName Constituent
--------- -----------
A         B
A         K
A         L

(3 row(s) affected)
0 голосов
/ 27 мая 2010

Для полноты картины я приложил весь файл сценария sql, который устанавливает проблему и показывает решение. Опять Хаттип к КМ.

 use tempdb
go

if OBJECT_ID('dbo.Hierarchical') is not null
    drop table dbo.Hierarchical

create table dbo.Hierarchical
(
     colID          int         not null identity(1,1) primary key
    ,GroupName      varchar(5)  not null
    ,IsAtomic       bit         not null
    ,Constituent    varchar(5)  null
)

set nocount on
insert into dbo.Hierarchical values ('A',0,'B')
insert into dbo.Hierarchical values ('A',0,'C')
insert into dbo.Hierarchical values ('B',1,'B')
insert into dbo.Hierarchical values ('C',0,'K')
insert into dbo.Hierarchical values ('C',0,'L')
insert into dbo.Hierarchical values ('D',0,'E')
insert into dbo.Hierarchical values ('D',0,'F')
insert into dbo.Hierarchical values ('D',0,'G')
insert into dbo.Hierarchical values ('E',1,'E')
insert into dbo.Hierarchical values ('F',1,'F')
insert into dbo.Hierarchical values ('G',0,'H')
insert into dbo.Hierarchical values ('G',0,'I')
insert into dbo.Hierarchical values ('H',1,'H')
insert into dbo.Hierarchical values ('I',1,'I')
insert into dbo.Hierarchical values ('J',1,'J')
insert into dbo.Hierarchical values ('K',1,'K')
insert into dbo.Hierarchical values ('L',1,'L')
insert into dbo.Hierarchical values ('M',1,'M')
insert into dbo.Hierarchical values ('N',1,'N')
set nocount off

--  see what the over nomalized table looks like 
--  before you call the CTE. Notice how A has
--  Constiuents B, and C. And further down
--  C is made up of K, and L.

--  select * from dbo.Hierarchical

go


--  Use the CTE to 
;WITH HierarchicalTree AS 
( 
    SELECT  
        GroupName, Constituent,  1 AS LevelOf 
        FROM dbo.Hierarchical
        --WHERE GroupName=@Start 
    UNION ALL 
        SELECT  
            t.GroupName, h.Constituent, t.LevelOf+1 
        FROM HierarchicalTree         t 
            INNER JOIN dbo.Hierarchical  h ON t.Constituent=h.GroupName 
        WHERE h.Constituent!=h.GroupName AND h.IsAtomic=0 
) 


--  Now, notice this query will give us A with the it's 
--  Constiuent elements B, K, and L
SELECT 
    t.GroupName,t.Constituent, h.IsAtomic, t.LevelOf
    FROM HierarchicalTree        t 
        INNER JOIN  dbo.Hierarchical h  ON  t.Constituent=h.GroupName 
    --WHERE h.IsAtomic=1 
    Where h.Constituent = h.GroupName
order by 
    t.GroupName

if  OBJECT_ID('tempdb..Hierarchical') is not null
    drop table  dbo.Hierarchical
0 голосов
/ 26 мая 2010

Ну, это делает то, о чем вы просили, но это будет работать, только если оно будет вложено один раз. Если вам нужна рекурсия, вам придется использовать CTE.

select a.GroupName,
        b.Constituent

From dbo.Hierarchical a

Left Join dbo.Hierarchical b on a.Constituent = b.GroupName

Это то, что вам нужно, или я полностью упустил суть?

...