加入一张桌子给自己

时间:2011-10-17 13:58:38

标签: sql sql-server sql-server-2008 recursion recursive-query

这是我的数据库表模板中的一个。

Id int PK
Title nvarchar(10) unique
ParentId int 

这是我的问题。如果我在“Id”和“ParentId”列之间创建关系,是否会出现问题? (我的意思是创建一个表与自身之间的关系) 我需要一些关于插入或更新期间可能发生的问题的建议或者在开发step.thanks

时删除操作

7 个答案:

答案 0 :(得分:5)

你可以完美地加入桌子。

但是,您应该知道,您的设计允许您拥有多个层次结构。由于您使用的是SQL Server(假设为2005或更高版本),因此可以使用递归CTE获取树结构。

概念准备证明:

declare @YourTable table (id int, parentid int, title varchar(20))

insert into @YourTable values
(1,null, 'root'),
(2,1,    'something'),
(3,1,    'in the way'),
(4,1,    'she moves'),
(5,3,    ''),
(6,null, 'I don''t know'),
(7,6,    'Stick around');

查询1 - 节点级别:

with cte as (
    select Id, ParentId, Title, 1 level 
    from @YourTable where ParentId is null

    union all

    select yt.Id, yt.ParentId, yt.Title, cte.level + 1
    from @YourTable yt inner join cte on cte.Id = yt.ParentId
)
select cte.*
from cte 
order by level, id, Title

答案 1 :(得分:3)

不,你可以自己加入你的表,不会有任何问题。你在谈论插入,更新,删除操作中的哪些类型的问题?您可以在添加新记录之前检查一些条件,例如ParentId是否存在,或者您可以在删除父级时检查它是否存在。

您可以像以下一样进行自我加入:

select t1.Title, t2.Title as 'ParentName'
from table t1 
left join table t2 
on t1.ParentId = t2.Id  

答案 2 :(得分:2)

你在这里有很多好的答案。另一件需要考虑的是参照完整性。您可以在表上指向同一个表中另一列的外键。观察:

CREATE TABLE tempdb.dbo.t
(
    Id INT NOT NULL ,
    CONSTRAINT PK_t PRIMARY KEY CLUSTERED ( Id ) ,
    ParentId INT NULL ,
    CONSTRAINT FK_ParentId FOREIGN KEY ( ParentId ) REFERENCES tempdb.dbo.t ( Id )
)

通过这样做,您可以确保在ParentId列中不会出现垃圾。

答案 3 :(得分:1)

它被称为Self Join,它可以添加到表中,如下例

select e1.emp_name 'manager',e2.emp_name 'employee'
from employees e1 join employees e2
on e1.emp_id=e2.emp_manager_id 

答案 4 :(得分:1)

我在菜单层次结构的表上看到这样做没有错误你不应该有任何问题提供你的插入/更新/删除查询写得很好。

例如,当您插入检查父ID是否存在时,当您删除检查时,如果此操作合适,则删除所有子项,或者不允许删除具有子项的项。

答案 5 :(得分:0)

这样做很好(这是一种并不罕见的模式)。您必须确保将子记录添加到实际存在的父记录等,但此处与任何其他约束不同。

您可能希望查看递归公用表表达式:

http://msdn.microsoft.com/en-us/library/ms186243.aspx

作为查询整个“树”记录的一种方式。

答案 6 :(得分:0)

这不是问题,因为这是一种在现实生活中常见的关系。如果您没有父级(发生在顶层),则需要将此字段保留为“null”,然后才能正确更新和删除传播。