Сложная логическая проблема - как создать основанное на множестве решение для этого запроса? - PullRequest
4 голосов
/ 01 марта 2010

Используя SQL Server 2008 и любые доступные функции TSQL, я пытаюсь выяснить, как, если существует решение на основе множеств, не включающее временную таблицу, для следующей проблемы:

При заданном набореузлов, которые имеют отношение родитель-потомок, и набор пар ключ-значение, которые применяются к каждому, и учитывая, что значение (для данной пары ключ-значение) на более глубоком уровне иерархии узлов переопределит значение стот же ключ, который унаследован от узла-предка, выберите:

  1. полный набор пар ключ-значение, которые применяются к данному узлу
  2. набор унаследованных значений для этого узла

Схема выглядит следующим образом:

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)
);

Набор результатов будет по существу включать столбцы KeyName, Value, InheritedValue.

Я пытался сделать это, используя обычное табличное выражение, но его логика немного хитрая.

Ответы [ 4 ]

3 голосов
/ 26 августа 2010

Я настроил таблицы Node и KeyValuePair в соответствии с вопросом и заполнил некоторыми примерами значений, так что моя иерархия была следующей:

Root
| ---
| | --- A1
| | --- A2
|
| --- B
| --- B1
| --- B2

Я назначил два свойства с именами «Свойство 1» и «Свойство 2», каждое из которых определено в корне со значениями «Корневая поддержка 1» и «Корневая поддержка 2» соответственно. В A я переопределил «Свойство 1» со значением «A Prop 1», а в B я переопределил «Свойство 2» со значением «B Prop 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)

Вызов решения Натана для узла A1 не приводит к появлению строк!

Предложение where в решении Натана должно быть условием соединения ключей и 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
2 голосов
/ 01 марта 2010

Вы должны рассмотреть возможность использования модели вложенного множества для хранения вашей иерархии. Вот ссылка, которая описывает это: http://mikehillyer.com/articles/managing-hierarchical-data-in-mysql/

Он поддерживает гораздо более дружественный к SQL подход к получению общей информации об иерархической информации.

Ваше требование может быть удовлетворено запросом на узле и одним присоединением к KeyValuePair.

0 голосов
/ 26 августа 2010

Это один из тех случаев, когда материализованный путь светит. Вот как я решил похожую проблему, используя ее:

Сохраните параметры конфигурации в виде иерархии в базе данных.

0 голосов
/ 01 марта 2010

Хорошо, я решил это сам. Возможно, есть и другие способы сделать это, но, похоже, это работает достаточно хорошо:

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
...