给出下表
catName catID parentID
=================================
vehicles 1 0
cars 2 1
sedans 3 2
animals 4 0
cows 5 4
鉴于catID
,我需要找到它的顶级父级(parentID = 0
)。
此查询每天执行50-100次。目前有100-200行(将来可能更多)。最多8级。我在考虑三种选择:
topParentID
(最不利)哪种效率最高?
答案 0 :(得分:4)
SQL2008 +:
要存储层次结构,SQL Server包含HIERARCHYID数据类型。以上数据可以进行转换"使用HIERARCHYID
"值"因此:
catName catID parentID hierarchyNode
=============================================
vehicles 1 0 /1/
cars 2 1 /1/2/
sedans 3 2 /1/2/3/
animals 4 0 /4/
cows 5 4 /4/5/
转换后,我会删除parentID
列。
HIERARCHYID是SQLCLR系统数据类型,包括以下methods:
要获得父节点,我将使用这些方法:
DECLARE @node HIERARCHYID
SET @node = '/1/2/3/'
SELECT
currentNodeLvl= @node.GetLevel(), --> 3
parentAsHID = @node.GetAncestor(@node.GetLevel() - 1), --> 0x58
parentAsString= @node.GetAncestor(@node.GetLevel() - 1).ToString()--> /1/
更多,我会在hierarchyNode
列上创建一个索引:
CREATE UNIQUE INDEX IUN_Table_hierarchyNode
ON dbo.Table(hierarchyNode)
,最终查询将是:
SELECT ..., prt.catID AS parentID
FROM dbo.Table crt -- Curent node
LEFT/INNER JOIN -- It depends on hierarchyID nullability
dbo.MyTable prt -- Parent node
ON @node.GetAncestor(crt.hierarchyID.GetLevel() - 1).ToString() = prt.hierarchyID
答案 1 :(得分:2)
对于大型数据集,请使用桥接表。
在规模(数据仓库规模)中,我知道解决此问题的最有效方法是通过桥接表。查看http://www.askjohnobiee.com/2013/08/how-to-bridge-tables-and-many-to-many.html了解基础知识。
您最终维护的物理表具有一行,该行将每个父对象与每个子对象和子对象(以及从每个对象到自身)匹配。它维护很重(因为它必须在任何关系发生变化时进行更新),但查询非常有效,即使对于大型数据集也是如此。
在您的示例中,我使用以下架构构建(并填充)桥接表:
CREATE TABLE BridgeCategories
(
ParentCategoryID int,
ParentCategoryLevel tinyint,
ChildCategoryID int,
ChildCategoryLevel tinyint,
PRIMARY KEY (ParentCategoryID, ChildCategoryID)
)
-- add an index for your particular query
CREATE NONCLUSTERED INDEX ix_BridgeCategories_ByChildIDAndParentLevel
ON BridgeCategories (ChildCategoryID, ParentCategoryLevel) INCLUDE (ParentCategoryID)
当您填充BridgeCategories
表时,我会根据它们在层次结构中的距离设置适当的级别(即,在您的示例中,类别ID 1 - “车辆”将具有0,而ID 2 - “轿车”的等级为2)。
在您的示例中,(我认为)以下查询将填充具有上述结构的桥接表,假设您的源表名为 DimCategories
。
TRUNCATE TABLE BridgeCategories;
declare @currentLevel tinyint;
declare @MAX_LEVELS tinyint;
set @currentLevel = 0;
set @MAX_LEVELS = 16;
-- seed your root level entries
insert into BridgeCategories
SELECT
catID, @currentLevel, catID, @currentLevel
from DimCategories c
WHERE
c.parentID = 0;
set @currentLevel = @currentLevel + 1
while (@currentLevel < @MAX_LEVELS)
BEGIN
-- add any current level parent -> child mappings
insert into BridgeCategories
SELECT
b.ParentCategoryID,
b.ParentCategoryLevel,
c.catID,
@currentLevel
from BridgeCategories b
join DimCategories c
on b.ChildCategoryID = c.parentID
-- add the current level self-referencing entries
insert into BridgeCategories
SELECT
c.catID,
@currentLevel,
c.catID,
@currentLevel
from BridgeCategories b
join DimCategories c
on b.ChildCategoryID = c.parentID
group by c.catID
set @currentLevel = @currentLevel + 1
end
使用此结构,您可以运行以下查询以获取任何@catID的根父catID。
select
ParentCategoryID
from BridgeCategories b
where
b.ChildCategoryID = @catID
and b.ParentCategoryLevel = 0
如果您想深入了解,可以查看有关Ralph Kimball数据仓库概念的更多信息。