我有一张这样的表:
Item
{
int ItemID
int ParentID
string Name
}
Item实际上是较大的表Object的一个子集:
Object
{
int ObjectID
string Color
}
所以ItemID
是ObjectID
的FK。在Item
内,ParentID
可以引用另一个项目或父对象。
我想要做的是能够从Item关系中的一个叶子一直迭代到它的父节点,直到我最终确定给定的Item叶子从哪个ObjectID
下降。
我想在SQL中执行此操作。我正在使用SQL Server 2008。
这就是我的想法。我可以遍历项目ParentID
,直到我无法再将ParentID
加入另一个项目。这个ParentID
是我要返回的ObjectID
。
我一直在尝试使用内连接来实现这一点,但没有运气。我正在使用C#所以如果这可以在linq中完成,我不怀疑它可以没有非常低效,那也没关系。
答案我去了:
WITH ObjectH (ParentID, ItemID, Level) AS
(
-- Base case
SELECT
ParentID,
ItemID,
1 as Level
FROM Item
WHERE ItemID = @param
UNION ALL
-- Recursive step
SELECT
i.ParentID,
i.ItemID,
oh.Level + 1 AS Level
FROM Item i
INNER JOIN ObjectH oh ON
c.ItemID = oh.ParentID
)
SELECT TOP 1 ParentID
FROM ObjectH
ORDER BY Level DESC
这很有效。
答案 0 :(得分:1)
我尝试使用递归SQL Server CTE执行此操作。
从逻辑上讲,这就是CTE的工作原理,但这应该是我从未使用过与你的模式完全相同的模式。
通常SQL中的树结构没有附加的父“Object”表。 (看起来你正在模仿你的对象在db中完全按1:1设计?如果我是你,我会重新审视那个模式)
尝试一下,让我知道它是否有效。
编辑:稍微更改了基本查询条件
EDIT2:更改了查询以使其特定于一个项目
WITH ObjectHierarchy (ItemID, Name, ParentID, Level) AS
(
SELECT
ItemID,
Name,
ParentID,
1 as Level
FROM Item it, Object ob
WHERE it.ParentID = ob.ObjectID
AND ob.ItemID = @itemIdToBeSearched
UNION ALL
SELECT
i.ItemID,
i.Name,
i.ParentID,
oh.Level + 1 AS Level
FROM Item i
INNER JOIN ObjectHierarchy oh ON
i.ParentID = oh.ItemID
AND oh.ItemID = @itemIdToBeSearched
)
SELECT parentID
FROM ObjectHierarchy
WHERE LEVEL = 1
答案 1 :(得分:1)
首先,允许ParentID列将两个不同的表作为“外键”引用是一种可怕的设计。您可能已经意识到这一点,因为您在编写此查询时遇到了困难。
话虽如此,假设您处于无法重新设计架构的位置,我会通过创建一个代表Item“应该”的视图来解决这个问题,然后使用传统的递归方法该视图上的CTE方法用于遍历层次结构。
create view vwItem
as
select i.ItemID,
case when o.ObjectID is null then i.ParentID else null end as ParentID,
o.ObjectID, Name
from Item i
left join Object o
on i.ParentID = o.ObjectID
go
;with cteItemList as (
select i.ItemID, i.ParentID, i.ObjectID, i.Name, 1 as Level
from vwItem i
where i.ParentID is null
union all
select i.ItemID, i.ParentID, i.ObjectID, i.Name, il.Level+1 as Level
from vwItem i
inner join cteItemList il
on i.ParentID = il.ItemID
)
select *
from cteItemList
order by Level, ItemID
答案 2 :(得分:0)
只需在SQL中创建一个为您迭代的标量函数,并将其包含在模仿您的表的视图中,但将该函数的结果添加为列。然后,您将LINQ对象基于视图,并在代码中具有ParentID。