存储可覆盖的分层设置

r.z*_*rei 3 sql-server hierarchy

我在互联网上搜索并找到了关于软件工程 SE 上的分层设置覆盖的问题模式。它准确地描述了我的需求,唯一的区别是我需要将设置存储在 SQL Server 数据库中。

如何在 SQL Server 中实现它?

每当我选择 的设置时level1-child1,我都希望child1level1. 例如:

level1: max-value:100;  min-value:10;  enable-alarm:true;
level-child1: min-value:30;
Run Code Online (Sandbox Code Playgroud)

选择后:

level1-child1: max-value:100; min-value:30; enable-alarm:true;
Run Code Online (Sandbox Code Playgroud)

目前我使用层次结构路径来实现层次结构。

Dav*_*ett 5

您没有提供有关当前结构的大量细节,因此我假设层次结构中的每个节点都在一个简单的表中,具有像这样的单父关系,并且路径是一串 ID 之类的/<rootNodeID>/<GPNodeID>/<PNodeID>/<LeadNodeID>,并且您打算这样做将设置存储在属性包排列中,而不需要在将新设置添加到应用程序逻辑时更新数据库结构,结果如下:

Nodes                 NodeSettings
=============         ============      Settings
NodeID   (PK) <--.--  NodeID  (FK)      =========
ParentID (FK) ---'    Name    (FK) ---> Name (PK)
FullPath              Value             
OtherProp1
OtherProp2
Run Code Online (Sandbox Code Playgroud)

在这种安排中,您可以将所有具有值的设置从给定位置向上拉到树的任何位置(值更接近,如下所示:

SELECT Name  = s.Name
       Value = (SELECT TOP 1 ns.value
                FROM   NodeSetting ns
                JOIN   Nodes n ON n.NodeID = ns.NodeID AND '<PathToTargetNode>' LIKE n.FullPath+'%'
                WHERE  ns.Name = s.Name
                ORDER BY LEN(n.FullPath) DESC
               )
FROM   Settings s
Run Code Online (Sandbox Code Playgroud)

如果您有很多设置,那么使用这样的子查询可能不够高效,否则应该没问题。更令人担忧的是使用LIKE这种方式:它将无法正确使用 Nodes.FullPath 上的任何索引,因此可以为子查询的每次调用执行索引扫描(或更糟的是,表扫描)。在我的头顶上,我想不出一种方法来显着优化它作为单个查询而不添加新结构到节点之间的关系的存储,例如在上级和下级之间保持映射,例如:

RelationshipDistance
=======================
Ascendant  (FK->NodeID)
Descendant (FK->NodeID)
Distance
Run Code Online (Sandbox Code Playgroud)

(确保将节点与自身的关系存储为 AscNode='NodeID', DescNode='NodeID', Distance=0)。然后你可以这样做:

SELECT Name  = s.Name
       Value = (SELECT TOP 1 s2.value
                FROM   RelationshipDistance r
                JOIN   Settings s2 ON n.NodeID = s.NodeID AND s2.Name = s.Name
                WHERE  r.Descendant = '<IDOfNodeYouAreLookingFor>'
                ORDER BY r.Distance DESC
               )
FROM   Setting s
Run Code Online (Sandbox Code Playgroud)

这里的缺点是需要维护额外的结构(通过触发器或在代码的另一层工作)。

当然,这是假设您想从单个语句返回设置。您始终可以定义一个过程,该过程在收集临时表或表变量中的设置的路径上走,向根添加在每一步找到的新设置 - 这可能比导致索引/表的单个语句版本更有效扫描。