查询特定值的树

时间:2013-09-13 14:32:39

标签: sql sql-server-2008 tree sql-function

我是一个SQL新手,所以我绝对可以使用一些帮助来解决特定查询的一般设计。我将给出一个SQL示例,说明我在下面尝试做什么。它可能包含一些语法错误,我为此道歉 - 我只是在运行和测试之前试图让设计失效!

旁注 - 我对设计方案有0控制权,因此重新设计不是一种选择。由于我的疏忽,我的示例表可能有错误,但自下而上值搜索的整体设计方案将保持不变。我正在查询已经填充了大量数据的现有数据库。

场景是这样的:有一个元素树。每个元素都有一个ID和一个父ID(下面的表格布局)。父ID是自身的递归外键。第二个表包含值。每个值都有一个elementID,它是元素表的外键。因此,要获取特定元素的特定变量的值,必须连接两个表。

变量层次结构通过继承方式进入自下而上。如果您有一个元素并想要获取其变量值,那么首先要查看该元素。如果它没有值,则检查元素的父级。如果这不检查父母的父母 - 一直到顶部。 每个变量都保证在到达顶部时有一个值!(如果我搜索变量ID 21-我知道21将存在。如果不在底部,那么肯定在顶部)树上的最低元素获得优先权,但是如果底部元素具有该变量的值,则不要再进一步了!

表格大致如下:

Element_Table
--------------
elementID (PK)
ParentID (FK to elementID)

Value_Table 
--------------
valueID (PK)
variableID
value (the value that we're looking for)
elementID (FK to Element_Table.elementID)

所以,我要做的是创建一个干净利落的功能(关键词在这里。好,干净,高效的代码)搜索,自下而上,在树上寻找变量值。一旦找到它 - 返回该值并继续前进!

这是我正在思考的一个例子:

CREATE FUNCTION FindValueInTreeBottomUp
(@variableID int, @element varchar(50))
RETURNS varchar(50) 
AS
BEGIN
DECLARE @result varchar(50)
DECLARE @ID int
DECLARE @parentID int

SET @result = NULL, @ID = @element
WHILE (@result IS NULL)
    BEGIN
       SELECT @result = vals.value, @parentID = eles.ParentID
       FROM Value_Table vals 
       JOIN Element_Table eles 
       ON vals.elementID = eles.elementID
  WHERE eles.elementID = @ID AND vals.variableID = @variableID
  IF(@result IS NULL)
      @ID = @parentID
      CONTINUE
  ELSE
      BREAK
END

RETURN @result
END

如果有任何语法错误,我再次道歉。仍然是一个SQL新手,还没有运行这个!我特别是函数的新手 - 我可以整天查询,但函数/ sprocs对我来说仍然是新的。

那么,那里的SQL大师 - 你能想到更好的方法吗?表格的设计不会改变;我无法控制。我所能做的就是生成查询以检查现有的设计。

1 个答案:

答案 0 :(得分:1)

我认为你可以做这样的事情(它未经测试,必须在sql小提琴中尝试):

;with cte1 as (
    select e.elementID, e.parentID, v.value
    from Element_Table as e
        left outer join Value_Table as v on e.elementID = e.elementID and v.variableID = @variableID
), cte2 as (
    select v.value, v.parentID, 1 as aDepth
    from cte1 as v
    where v.elementID = @elementID
    union all
    select v.value, v.parentID, c.aDepth + 1
    from cte2 as c
    inner join cte1 as v on v.elementID = c.ParentID
    where c.value is null
)
select top 1 value
from cte2
where value is not null
order by aDepth

测试基础设施:

declare @Elements table (ElementID int, ParentID int)
declare @Values table (VariableID int, ElementID int, Value nvarchar(128))
declare @variableID int, @elementID int

select @variableID = 1, @elementID = 2

insert into @Elements
select 1, null union all
select 2, 1

insert into @Values
select 1, 1, 'test'

;with cte1 as (
    select e.elementID, e.parentID, v.value
    from @Elements as e
        left outer join @Values as v on e.elementID = e.elementID and v.variableID = @variableID
), cte2 as (
    select v.value, v.parentID, 1 as aDepth
    from cte1 as v
    where v.elementID = @elementID
    union all
    select v.value, v.parentID, c.aDepth + 1
    from cte2 as c
        inner join cte1 as v on v.elementID = c.ParentID
    where c.value is null
)
select top 1 value
from cte2
where value is not null
order by aDepth