棘手的逻辑问题 - 如何为此查询创建基于集合的解决方案?

时间:2010-03-01 10:10:04

标签: sql sql-server tsql hierarchy

使用SQL Server 2008和TSQL的任何可用功能,我试图找出如何针对以下问题存在不涉及临时表的基于集合的解决方案:

给定一组具有父子关系的节点,以及一组适用于每个节点的键值对,并给出 在节点层次结构的更深层次上的值(对于给定的键值对)将覆盖具有相同键的值 继承自祖先节点,选择:

  1. 适用于给定节点的全套键值对
  2. 该节点的继承值集合
  3. 架构如下:

    create table Node
    (
        ID bigint identity primary key,
        ParentID bigint null foreign key references Node(ID),
        Name nvarchar(100)
    );
    
    create table KeyValuePair
    (
        ID bigint identity primary key,
        KeyName nvarchar(100) not null,
        Value nvarchar(1000) not null,
        NodeID bigint not null foreign key references Node(ID),
    
        unique (KeyName, NodeID)
    );
    

    结果集基本上包括KeyNameValueInheritedValue列。

    我一直在尝试使用公共表表达式来执行此操作,但它的逻辑有点棘手。

4 个答案:

答案 0 :(得分:3)

我根据问题设置了Node和KeyValuePair表,并填充了一些示例值,以便我的层次结构如下:


| ---一个
| | --- A1
| | --- A2
|
| ---乙
| --- B1
| --- B2

我分配了两个名为“Property 1”和“Property 2”的属性,每个属性在root中定义,分别为“Root Prop 1”和“Root Prop 2”。在A中,我用值“A Prop 1”覆盖“Property 1”,在B中,我用值“B Prop 2”覆盖“Property 2”。

set identity_insert Node on
insert into Node(ID,ParentID,Name)
values (1,null,'Root'),(2,1,'A'),(3,1,'B'),(4,2,'A1'),(5,2,'A2'),
       (6,3,'B1'),(7,3,'B2')
set identity_insert Node off

insert into KeyValuePair(KeyName, [Value], NodeID)
values ('Property 1','Root Prop 1',1),
('Property 2','Root Prop 2',1),
('Property 1','A Prop 1',2),
('Property 2','B Prop 2',3)

调用Nathan的节点A1解决方案不会产生任何行!

Nathan解决方案中的where子句应该是keys和v之间连接的条件,导致下面显示的修改过程(我也将DataValue重命名为KeyValuePair以与原始问题保持一致):

create procedure dbo.ListDataValues
    @nodeid bigint
as
begin
    with nodes as (
        select ID, ParentID, 0 as Level
        from Node n where ID=@nodeid
        union all
        select n.ID, n.ParentID, c.Level+1 as Level
        from Node n inner join nodes c on c.ParentID = n.ID
    ),
    keys as (
        select distinct(KeyName)
        from KeyValuePair
        where NodeID in (select ID from nodes)
    )
    select
        keys.KeyName,
        v.Value,
        i.Value as [InheritedValue],
        i.NodeID as [InheritedFromNodeID]
    from
        keys
        left join KeyValuePair v on v.KeyName = keys.KeyName
                                     and v.NodeID = @nodeid
        left join KeyValuePair i on i.KeyName = keys.KeyName
            and i.NodeID = (select top 1 NodeID from KeyValuePair d
                            inner join nodes k on k.ID = d.NodeID
                            where Level > 0 and d.KeyName = i.KeyName
                            order by [Level])
end
go

这产生了预期的正确结果:

KeyName      Value   InheritedValue    InheritedFromNodeID
------------ ------- ----------------- --------------------
Property 1   NULL    A Prop 1          2
Property 2   NULL    Root Prop 2       1

答案 1 :(得分:2)

您应该考虑使用嵌套集模型来存储层次结构。这是一个描述它的链接: http://mikehillyer.com/articles/managing-hierarchical-data-in-mysql/

它支持更友好的SQL方法来检索有关分层信息的常见信息。

然后,您可以通过Node上的查询和KeyValuePair的单个连接来满足您的要求。

答案 2 :(得分:0)

好的,我自己解决了。可能还有其他方法可以做到,但这似乎运作得很好:

create procedure dbo.ListDataValues
    @nodeid bigint
as
begin
    with nodes as (
        select ID, ParentID, 0 as Level
        from Node n where ID=@nodeid
        union all
        select n.ID, n.ParentID, c.Level+1 as Level
        from Node n inner join nodes c on c.ParentID = n.ID
    ),
    keys as (
        select distinct(KeyName)
        from DataValue
        where NodeID in (select ID from nodes)
    )
    select v.KeyName, v.Value, i.Value as [InheritedValue], i.NodeID as [InheritedFromNodeID]
    from keys
    left join DataValue v on v.KeyName = keys.KeyName
    left join DataValue i on i.KeyName = keys.KeyName
        and i.NodeID = (select top 1 NodeID from DataValue d
                        inner join nodes k on k.ID = d.NodeID
                        where Level > 0 and d.KeyName = i.KeyName
                        order by Level)
    where v.NodeID = @nodeid
end

答案 3 :(得分:0)

这是物化路径闪耀的情况之一。以下是我使用它解决类似问题的方法:

Store your configuration settings as a hierarchy in a database.