2011-01-12 24 views
3

我使用的是分割功能(在social.msdn.com找到),並在查詢窗口SQL斯普利特 - 插入分級表結構

SELECT * FROM dbo.Split('/ABC/DEF/GHI/JKL', '/') 

我得到手動執行時以下

Id Name 
-- ---- 
1 
2 ABC 
3 DEF 
4 GHI 
5 JKL 

其中Id只是一個指示原始字符串內的位置的序號,並且名稱是該節點的名稱。尚無分層信息。

現在,下一步是將其放入數據庫中的分層數據結構中。我試圖在一個存儲過程中做到這一點,我的SQL技能就是這樣,我打了一堵牆。這裏就是我想要喜歡有:(注ID列以上不相關的ID或列的ParentId這裏)

Id ParentId Name FullName 
-- -------- ---- -------- 
1  NULL  ABC /ABC 
2  1  DEF /ABC/DEF 
3  2  GHI /ABC/DEF/GHI 
4  3  JKL /ABC/DEF/GHI/JKL 

我走了這麼遠我的SP(用param @FullName調用GetId) - GetId應返回與此節點關聯的Id。如果節點不存在,則應該創建該節點,並且應該返回來自該新行的ID - 換句話說,該SP的使用者在調用節點之前不應該關心或知道該節點是否存在:

DECLARE @count int 

-- // is there already a row for this node? 
SELECT @count = COUNT(CatId) 
FROM Category 
WHERE FullName = @FullName 

-- // if no row for this node, create the row 
-- // and perhaps create multiple rows in hierarchy up to root 
IF (@count = 0) 
BEGIN 
    SELECT * FROM Split(@FullName, '/') 
    -- // NOW WHAT ??? 
    -- // need to insert row (and perhaps parents up to root) 
END 

-- // at this point, there should be a row for this node 
-- // return the Id associated with this node 
SELECT Id 
FROM Category 
WHERE FullName = @FullName 

這些項目最終會通過一系列插入最終結束的分類表(鄰接列表)具有以下結構。

CREATE TABLE Category (
    Id int IDENTITY(1,1) NOT NULL PRIMARY KEY, 
    ParentId int NULL, 
    Name nvarchar(255) NOT NULL, 
    FullName nvarchar(255) NOT NULL) 

至於結果,我不希望產生在分類表中的ID列中的值,並需要得到每個節點的適當的ParentId。

處理路徑'ABC/DEF/GHI/JKL'和'/ ABC/DEF/XYZ/LMN/OPQ'後,我做了一個SELECT * FROM類別,我期望看到以下內容:

Id ParentId Name FullName 
-- -------- ---- -------- 
1  NULL  ABC /ABC 
2  1  DEF /ABC/DEF 
3  2  GHI /ABC/DEF/GHI 
4  3  JKL /ABC/DEF/GHI 
5  2  XYZ /ABC/DEF/XYZ 
6  5  LMN /ABC/DEF/XYZ/LMN 
7  6  OPQ /ABC/DEF/XYZ/LMN/OPQ 

Q:將有可能回調到該SP開始遞歸在最外側的節點,直到存在的節點或我們的最終母公司?東西的效果:

GetId(@FullName) 
{ 
If Category exists with @FullName 
    return CatId 
Else // row doesn't exist for this node 
    Split @FullName, order by Id DESC so we get the leaf node first 
    Create Category row 
     @FullName, 
     @Name, 
     @ParentId = Id of next FullName (call GetId with FullName of next row from Split) 
} 
+0

你在什麼版本的SQL Server?如果2008年你考慮過[hierarchyid](http://msdn.microsoft.com/en-us/magazine/cc794278.aspx)? –

+0

我在SQL Server 2008上 –

+0

你表達路徑的方式讓我想起了很多'hierarchyid'格式。我沒有真正使用它自己,雖然所以不知道它是否會更適合您的目的比毗鄰列表模型... –

回答

3

您可以RowNumbering

With TMP AS (
    SELECT Id, Data as Name, RN=ROW_NUMBER() over (Order by Id ASC) 
    FROM dbo.Split('/ABC/DEF/GHI/JKL', '/') 
    where Data > '' 
), TMP2 AS (
    SELECT TOP 1 RN, CONVERT(bigint, null) ParentId, Name, convert(nvarchar(max),'/' + Name) FullName 
    From TMP 
    Order by RN 
    union all 
    SELECT n.RN, t.RN, n.Name, t.FullName + '/' + n.Name 
    from TMP2 t 
    inner join TMP n on n.RN = t.RN+1) 
select * 
from tmp2 
order by RN 

使用CTE來實現這一目標,結合現在的第二部分,這就將整個層次結構,但與ID = 1開始

IF (@count = 0) 
BEGIN 
    With TMP AS (
     SELECT Id, Data as Name, RN=ROW_NUMBER() over (Order by Id ASC) 
     FROM dbo.Split('/ABC/DEF/GHI/JKL', '/') 
     where Data > '' 
    ), TMP2 AS (
     SELECT TOP 1 RN, CONVERT(bigint, null) ParentId, Name, convert(nvarchar(max),'/' + Name) FullName 
     From TMP 
     Order by RN 
     union all 
     SELECT n.RN, t.RN, n.Name, t.FullName + '/' + n.Name 
     from TMP2 t 
     inner join TMP n on n.RN = t.RN+1) 
    insert Category(CatId, ParentId, Name, FullName) --<< list correct column names 
    select RN, ParentId, Name, FullName 
    from tmp2 
    order by RN 
END 
+0

我還不確定你想要做什麼與第二部分。最後的(重新)構造的FullName無疑會匹配輸入@FullName,那麼拆分的目的是什麼? – RichardTheKiwi

+0

@cyberwiki我想要做一系列的插入操作來生成分層結構到鄰接列表數據庫模式中。我不確定上述解決方案如何適合插入場景。 –

+0

@ Ed.S。仍然不是100%確定。你想測試_full_ name是否存在,如果它不插入整個樹(其中的部分可能已經存在,例如/ ABC可能存在於其他地方)。這些ID將進入標識列,因此parentID需要調整? – RichardTheKiwi