2016-08-02 64 views
1

我需要編寫一個存儲過程來返回從兒童到父母的訂單上的一些數據。描述我想要做什麼很複雜,但讓我試試它: 假設我們有這樣的層次結構稱爲分類:家長> Child1> CHILD2> Child3,所有存儲在使用SQL HIERARCHYID:使用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 

最後我想選擇「樣本」 p十大新聞與此條件:

如果NewsOfWashington有10個消息,然後選擇它, 別的選擇NewsOfWestUSA, 別的選擇NewsOfUSA, 別的選擇新聞, 直到您達到十個

而且要選擇的順序是這樣的

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

我試過使用遞歸CTE,但找不到實現它的正確方法。

+0

通過'UNION'使用多個查詢? – Malk

+0

@Malk,不,不,不要,只是這兩個表我想先檢查,如果新聞標記與NewsOfWashington達到10或不,如果不從他的父母NewsOfWestUSA選擇等等... – Yasin

回答

0

完全竊取數據腳本米奇」的回答,這是不是太糟糕了:

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()方法上進行排序(這會返回給定值的層次結構深度)。

+0

幹得好!正如你所說的,我們也應該將米奇的回答也標記爲答案,因爲他也回答了這個問題,但是你的方法在某種程度上簡單易行。多謝兄弟。 – Yasin

+0

你*可以*擊中他的回答旁邊的小箭頭,以迅速擊中他的聲望。 :)我做了(感謝提醒!)。 –

+1

我是這麼做的,但是我的名聲還不夠高,無法反映出來 – Yasin

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; 
+0

我感謝您的幫助,但問題是,這些類別,'NewsOfWashington'等是動態的,我只是有cat_id/1/1/1/1/ 這怎麼能這樣做呢? – Yasin

+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 
+0

我也希望你的答案也是答案,因爲這也很好,但不幸的是它不可能標記多個! 感謝您的回答 – Yasin