好的,首先,如果你仔细阅读了整篇文章,请提前感谢,因为它可能在几个层面上非常痛苦。
但从好的方面来说,在阅读完整篇文章之后,我感觉答案非常明显和简单,所以你有这样做。
所以我会简单地告诉你这个问题,然后更详细地说:
果壳
Grandpappy.Grandpa.Dad.Me
。详细说明
以下是表明儿童和父母的表格。在这个例子中,我们将处理水果,蔬菜和行星。
我们来看看他们......
表1 = Planets
(我没有父母)
ID, Name
1, Earth
2, Saturn
表2 = Fruits
(我的父母要么是行星要么是水果)
ID, Name, PlanetName, FruitName
1, Kiwi, Earth, null
2, Strawberry, Saturn, null
3, Banana, null, Strawberry
表3 = Vegetables
(我的父母是行星或水果或蔬菜)
ID, Name, FruitName, PlanetName, VegetableName
1, Potato, Kiwi, null, null
2, Squash, null, Earth, null
3, Pumpkin, null, null, Potato
表4 = BigTable
(这将是主要慢查询使用的那个。它有一个只包含孩子名字的列,它可能是一个行星或水果或蔬菜)
ID, Name, OneOfTheThree
1, John, Earth
2, Steve, Kiwi
3, Joe, Saturn
4, Jane, Potato
我们有表格,我们有数据,我现在想做什么?
我想创建一个查询,查看BigTable中的所有OneOfTheThree值,并找出他们的血统是什么(爸爸,祖父等等),并将其返回给调用者。
所以我的想法就是这样做:
所以我这样做了:
我的观点
查看= vwEverybodyAndTheirParents
-- Planets
SELECT Name, null AS Parent
FROM Planets
UNION
-- Fruits
SELECT Name, PlanetName AS Parent
FROM Fruits
UNION
-- Vegetables
SELECT Name, CASE WHEN FruitName IS NOT NULL THEN FruitName WHEN PlanetName IS NOT NULL THEN Planet ELSE NULL END AS Parent
FROM Vegetables
好的,这给了我一切,它是父母。现在,对于抓取该视图的函数,给我一个完整祖先的句点分隔字符串:
我的功能
CREATE FUNCTION dbo.fnGetMyParent(@NameToGetParentsFor varchar(255))
RETURNS varchar(255)
AS
DECLARE @InternalName varchar(255)
DECLARE @ParentName varchar(255)
DECLARE @ConcatenatedParentStringToReturn varchar(max)
SELECT @ParentName = Parent
,@ConcatenatedParentStringToReturn = Name
FROM vwEverybody
WHERE Name = @NameToGetParentsFor
WHILE @ParentName IS NOT NULL
BEGIN
SELECT @InternalName = Name,
@ParentName = Parent
FROM vwEverybody
WHERE Name = @ParentName
SET @ConcatenatedParentStringToReturn = RTRIM(InternalName) + "." + RTRIM(@ConcatenatedParentStringToReturn)
END
RETURN @ConcatenatedParentStringToReturn
END
这个函数运行正常(虽然可能编码不好,性能不佳?),所以上面的所有例子都是这样称呼它:
dbo.fnGetMyParent('Potato')
我找回了连接的字符串:
Earth.Kiwi.Potato
问题
好的,现在最终解决问题......永远需要的大问题:
SELECT Name,
OneOfTheThree,
fnGetMyParent(OneOfTheThree) as HeirarchyOfParents
FROM BigTable
我可以看到为什么它可能需要花费很长时间才能执行需要随后抓取视图的函数。所以......
我的问题
非常感谢你,如果你做到这一点!
答案 0 :(得分:2)
首先使用sql时,应尽可能避免使用循环(除非情况要求)
其次,不需要视图或函数,因为您的查询应该可以一次编写。
select
bt.Name
,bt.OneOfTheThree
,p.Name+'.'+isnull(f.Name,'')+'.'+isnull(v.Name,'')+'.'+bt.Name as HeirarchyOfParents
from BigTable bt
left join Vegetables v
on bt.OneOfTheThree = v.name
left join Fruits f
on coalesce(v.FruitName,bt.OneOfTheThree) = f.Name
left join Planets p
on coalesce(f.PlanetName,v.PlanetName,bt.OneOfTheThree) = p.Name
如果表格与其他表格一致,您可以删除最后一个联接,因为它不会带来新信息(行星名称已经存在)。
如果你能够做到这一点,你可以带来的改进是表上的索引。
好的,有了这些新信息,我能想到的最简单方法如下:
;with ftemp as (
select
name as path
,PlanetName
,name as root
,name as name
,FruitName as parent
,0 as cnt
from fruits
union all
select
fruits.name + '.' + ftemp.path
,ftemp.PlanetName
,root
,fruits.name
,cnt+1
from fruits
join ftemp
on fruits.name= ftemp.parent
)
,fg as (
select
name
,max(cnt) as cnt
from ftemp
group by name
)
,f as (
select
ftemp.*
from ftemp
join fg
on ftemp.cnt = fg.cnt
and ftemp.name = fg.name
)
,vtemp (same ideea)
,vg (same ideea)
,v (same ideea)
select
bt.Name
,bt.OneOfTheThree
,p.Name+'.'+isnull(f.Path+'.','')+isnull(v.Path+'.','')+bt.Name as HeirarchyOfParents
from BigTable bt
left join v
on bt.OneOfTheThree = v.name
left join f
on coalesce(v.FruitName,bt.OneOfTheThree) = f.Name
left join Planets p
on coalesce(f.PlanetName,v.PlanetName,bt.OneOfTheThree) = p.Name
虽然采用了这种方法,但我不知道它会产生什么样的性能。因此,您需要完成查询和测试。
希望它有所帮助。