[英]Flattening a table that contains rows that reference other rows in SQL Server 2005
I am facing a problem that occasionally comes up when you deal with not fully normalized table. 我正面临一个问题,当你处理不完全规范化的表时偶尔会出现这个问题。 Here is the problem.
这是问题所在。 Imagine a table with 4 columns, and let's call this table dbo.Hierarchical.
想象一下有4列的表,让我们把这个表称为dbo.Hierarchical。 Here is the definition of the table:
这是表的定义:
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
)
This table can have a GroupName that is Atomic, which means that it doesn not have a component, or can not be Atomic. 此表可以具有Atomic的GroupName,这意味着它没有组件,或者不能是Atomic。 In this case, a GroupName can contain other GroupNames.
在这种情况下,GroupName可以包含其他GroupNames。
Lets fill the table with some data for clarity. 为了清楚起见,让我们在表格中填写一些数据。
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
Now if we look at a simple select * from dbo.Hierarchical we get the following: 现在,如果我们从dbo.Hierarchical看一个简单的select *,我们得到以下结果:
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
Whew, that was long winded. 哇,那是漫长的啰嗦。 Now, notice that the first two rows have GroupName A and Constiuents B and C. B is Atomic, so it has no further constiuents.
现在,注意前两行有GroupName A和Constiuents B和C. B是Atomic,所以它没有其他的constiuents。 C, however, has constiuents K, L (K and L are Atomic).
然而,C具有钾,L(K和L是原子)。 How can I create a view that will flatten this table out so that I only see GroupName and the Atomic constiuents.
如何创建一个将该表展平的视图,以便我只看到GroupName和Atomic constiuents。 In the case of GroupName A, I shoud see 3 rows
在GroupName A的情况下,我应该看到3行
A B
A K
A L
give this a try: 尝试一下:
--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
OUTPUT: OUTPUT:
GroupName Constituent
--------- -----------
A B
A K
A L
(3 row(s) affected)
Well this does what you have asked for but it will only work if it's nested once. 这就是你所要求的,但只有嵌套一次才会有效。 If you need recursion then you would have to use a CTE.
如果您需要递归,那么您将不得不使用CTE。
select a.GroupName,
b.Constituent
From dbo.Hierarchical a
Left Join dbo.Hierarchical b on a.Constituent = b.GroupName
Is this what you need or have I missed the point completely? 这是你需要的还是我完全错过了这一点?
For the sake of completeness, I've attached the entire sql script file that setups up the problem and shows the solution. 为了完整起见,我附加了整个sql脚本文件来设置问题并显示解决方案。 Again, Hattip to KM.
再次,Hattip到KM。
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
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.