我是一个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大师 - 你能想到更好的方法吗?表格的设计不会改变;我无法控制。我所能做的就是生成查询以检查现有的设计。
答案 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