我需要编写一个存储过程来返回从子项到父项的订单的一些数据。描述我想要做的事情有点复杂,但让我尝试一下: 想象一下,我们有这个层次结构叫做Categories:Parent> Child1> Child2> Child3,全部使用SQL HierarchyID存储:
Category Table
--------------
Cat_ID | Cat_Name
..............................
/1/ | News
/1/1/ | NewsOfUSA
/1/1/1/ | NewsOfWestUSA
/1/1/1/1/ | NewsOfWashington
我们已经使用以下类别保存了新闻:
News Table
-------------
News_ID | FK_Cat_ID | News_Content
.........................................
0001 | /1/ | one
0002 | /1/1/ | two
0003 | /1/1/1/ | three
0004 | /1/1/1/1/ | four1
0005 | /1/1/1/1/ | four2
0006 | /1/1/1/1/ | four3
0007 | /1/1/1/1/ | four4
最后我想在这个条件下选择sxample十大新闻:
如果 NewsOfWashington 有10条新闻,请选择它, 否则从 NewsOfWestUSA 中选择, 否则请从 NewsOfUSA 中选择, 否则从新闻中选择, 直到你达到十岁
要选择的顺序是
four4,four3,four2,four1,three,two,one
我尝试过使用递归CTE,但找不到合适的方法来实现它。
答案 0 :(得分:1)
要确定距离,请查找所有后代,然后按深度差异排序:
USE tempdb;
CREATE TABLE Categories (CatID hierarchyid not null primary key, Name nvarchar(255) not null);
CREATE TABLE News (NewsID int not null primary key, CatID hierarchyid not null, NewsContent nvarchar(max) not null);
INSERT INTO Categories
VALUES ('/1/', 'News'),
('/1/1/', 'NewsOfUSA'),
('/1/1/1/', 'NewsOfIndiana'),
('/1/2/', 'NewsOfUK');
INSERT INTO News
VALUES (1, '/1/', 'Aliens invaded'),
(2, '/1/1/', 'Aliens invaded the US'),
(3, '/1/1/1/', 'Aliens invaded the midwest'),
(4, '/1/2/', 'Aliens invaded the UK');
DECLARE @VisitorLocation hierarchyid = '/1/1/1/';
WITH
relevantCategories AS (
SELECT c.*, ABS(@VisitorLocation.GetLevel() - c.CatID.GetLevel()) as RelevanceDistance
FROM Categories c
WHERE @VisitorLocation.IsDescendantOf(c.CatID) = 1
)
SELECT TOP(10) n.*, c.RelevanceDistance
FROM relevantCategories c
INNER JOIN News n on n.CatID = c.CatID
ORDER BY RelevanceDistance ASC, n.NewsID DESC;
DROP TABLE Categories;
DROP TABLE News;
产地:
NewsID CatID NewsContent RelevanceDistance
-------- -------- ---------------------------- -------------------
3 0x5AD6 Aliens invaded the midwest 0
2 0x5AC0 Aliens invaded the US 1
1 0x58 Aliens invaded 2
答案 1 :(得分:0)
尝试以下操作,它将按您想要的顺序返回TOP 10:
SELECT TOP 10 CASE n.FK_Cat_ID
WHEN '/1/1/1/1/' THEN 0
WHEN '/1/1/1/' THEN 1
WHEN '/1/1/' THEN 2
WHEN '/1/' THEN 3
Else 4 END,*
FROM News as n
INNER JOIN Category as c
ON n.FK_Cat_ID = c.Cat_ID
ORDER BY 1;
答案 2 :(得分:0)
从Mitch的回答中完全窃取数据脚本,这不是太糟糕了:
CREATE TABLE Categories
(
CatID hierarchyid not null
primary key ,
Name nvarchar(255) not null
);
CREATE TABLE News
(
NewsID int not null
primary key ,
CatID hierarchyid not null ,
NewsContent nvarchar(max) not null
);
INSERT INTO Categories
VALUES ('/1/', 'News'),
('/1/1/', 'NewsOfUSA'),
('/1/1/1/', 'NewsOfIndiana'),
('/1/2/', 'NewsOfUK');
INSERT INTO News
VALUES (1, '/1/', 'Aliens invaded'),
(2, '/1/1/', 'Aliens invaded the US'),
(3, '/1/1/1/', 'Aliens invaded the midwest'),
(4, '/1/2/', 'Aliens invaded the UK');
-- actual answer begins here
select TOP(10) News.[NewsContent]
from dbo.Categories as parent
join dbo.Categories as child
on child.CatID.IsDescendantOf(parent.CatID) = 1
join News
on News.CatID = parent.CatID
WHERE child.Name = 'NewsOfIndiana'
order by News.CatID.GetLevel() DESC
基本上,我使用IsDescendentOf()
方法获取给定类别所属的类别,然后根据新的类别列表加入新闻项目,最后在{{1}上排序} method(返回给定值在层次结构中的深度)。