使用 SQL HierarchyID 到 select 分别从 Children 到 Parents

Using SQL HierarchyID to select respectively from Children to Parents

我需要为 return 编写一个存储过程,从 children 到 parents.It 的订单上的一些数据对于描述我想做的事情来说有点复杂,但让我试试它: 假设我们有一个名为 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

最后,我想 select 获得符合以下条件的示例前十条新闻:

If NewsOfWashington has 10 news then select it, else select from NewsOfWestUSA, else select from NewsOfUSA, else select from News, Until you reach ten

select编辑的顺序是

four4,four3,four2,four1,three,two,one

我尝试过使用递归 CTE,但找不到合适的实现方法。

试试看,它会return按照你想要的顺序排在前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;

要确定距离,查找所有后代,然后按深度差异排序:

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  

完全从 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() 方法来获取给定类别属于哪些类别,然后根据新的类别列表加入新闻项目,最后对 GetLevel() 方法(returns 给定值在层次结构中的深度)。