2015-09-30 94 views
4

我有表與分層,父子關係,並希望按該層次結構排序。表是:如何按層次結構排序

id|parent|type 
-------------- 
1 |0  |1 
2 |0  |1 
3 |0  |1 
4 |0  |2 
5 |0  |2 
6 |2  |2 
7 |3  |2 

而作爲結果,我想這一點:

id|parent|type 
-------------- 
1 |0  |1 
2 |0  |1 
6 |2  |2 
3 |0  |1 
7 |3  |2 
4 |0  |2 
5 |0  |2 

所以我希望得到的東西像一個樹視圖,其中1型排列第一,在最後2型。

現在我試圖使用遞歸,但順序是錯誤的:

with cte as 
(
    select id, parent, type from tbl where id=1 
    union all 
    select id, parent, type, 
    ROW_NUMBER()over(
    order by 
     (case when t.type = 1 then 1 
      when t.type = 2 then 2 
    else 1000 
    end) as rn 
    from tbl t 
    inner join cte c on c.id=t.parent 
) 
select * from cte 
order by rn 

我怎樣才能做到這一點?

+0

連接方式是你最好的朋友,如果你想讓這樣的樹像代表http://docs.oracle.com/cd/B19306_01/server.102/b14200/queries003.htm – istovatis

+0

@istovatis那真的很酷,但我正在使用MS Sql服務器 – Gleb

+0

你能解釋'type = 2'應該如何解釋像4和5這樣的值嗎?例如,爲什麼你把它們放在6之後,而不是之前?爲什麼他們有這個'類型'的價值,首先... –

回答

1

使用順序hierarchyid與cte很簡單,不用於遞歸關係測試

DECLARE @Data table (Id int identity(1,1) primary key, Parent int, Type int) 

INSERT @Data VALUES 
(0, 1), 
(0, 1), 
(0, 1), 
(0, 2), 
(0, 2), 
(2, 2), 
(3, 2) 

SELECT * FROM @Data 

;WITH level AS 
(
    -- The root, build the hierarchy by /{Type}.{Id}/, where Type is important then Id 
    SELECT *, -- 0 AS Level, 
     '/' + CONVERT(varchar(max), Type + 0.1 * Id) + '/' AS Ordering 
    FROM @Data 
    WHERE Parent = 0 
    UNION ALL 
    -- Connect the parent with appending the hierarchy 
    SELECT d.*, -- c.Level + 1, 
     c.Ordering + CONVERT(varchar(max), d.Type + 0.1 * d.Id) + '/' 
    FROM @Data d INNER JOIN level c ON d.Parent = c.Id 
) 
SELECT Id, Parent, Type FROM level 
ORDER BY CAST(Ordering as hierarchyid) -- The key part to convert data type 

SQL Fiddle

+0

這幾乎是我所需要的,謝謝。但是還有一個問題,現在層次結構是正確的,但是類型3和類型4的對象覆蓋了類型1和類型2的對象。 type1和type2也有較小的id then3和type4。我該如何解決這個問題? – Gleb

+0

@Gleb很高興有更多的數據來測試你的問題 – Eric

+0

通過乘法解決了這個問題。 \t(情況下,當v.type = 'TYP1' 然後-0.1 \t \t當v.type = '2型' 然後-0.1 \t \t別的0.1 \t \t端)* r.id)+ '/'。謝謝。 – Gleb

3

可以用下面的遞歸CTE來完成:

WITH cte AS (
    SELECT *, 
    CAST(ROW_NUMBER() OVER(ORDER BY id) AS REAL) rn, 
    1 level 
    FROM tbl 
    WHERE parent = 0 
    UNION ALL 
    SELECT t2.*, 
    cte.rn + (CAST(ROW_NUMBER() OVER(ORDER BY t2.id) AS REAL)/POWER(10, cte.level)) rn, 
    cte.level + 1 level 
    FROM tbl t2 INNER JOIN cte 
    ON t2.parent = cte.id 
) 
SELECT id, parent, type 
FROM cte 
ORDER BY rn 

SQLFiddle更復雜的樣本數據(更深的層次, 「無序親子ID的」)

+0

除非數據總是那麼簡單,否則會失敗。例如,超過1個嵌套層次將會破壞它。 –

+0

這很好,但有一個細節,身份證可能會更大,然後父母身份證。 – Gleb

+0

@Gleb - 修改後的答案,適用於所有更深層次結構,「無序父母 - 孩子ID」,請參閱小提琴。 – Amit

0
with cte as 
(
    select *, 1 level, row_number() over (order by id) rn 
    from tbl 
    where parent = 0 
    union all 
    select t.*, cte.level + 1 level, cte.rn 
    from cte 
    inner join tbl t on cte.id = t.parent 
) 
select id, parent, type from cte order by rn, level