2017-08-07 10 views
2

既存の表は、このように見えるにパス列をブレークダウンSQL:は、階層データ

Categories 
---------------------------------------------- 
Drinks\Soda 
Drinks\Juice\Fruit Juice\Apple Juice\Sugar Free 
Food\Fruit\Oranges 
Food\Fruit\Apples\Golden 
Food\Fruit\Apples\Red Delicious 
Food\Vegetables\Potatoes 
Food\Meat 
Food 

そして、私はこのように、階層データテーブルにそれを処理する必要があります。

Id | ParentId | Category | Full path 
------------------------------------------ 
1 | null  | Drinks  | Drinks 
2 | 1  | Soda  | Drinks\Soda 
3 | 1  | Juice  | Drinks\Juice 
4 | 3  | Fruit Juice | Drinks\Juice\Fruit Juice 
5 | 4  | Apple Juice | Drinks\Juice\Fruit Juice\Apple Juice 
6 | 5  | Sugar Free | Drinks\Juice\Fruit Juice\Apple Juice\Sugar Free 
7 | null  | Food  | Food 
8 | 7  | Fruit  | Food\Fruit 
9 | 8  | Oranges  | Food\Fruit\Oranges 
10 | 8  | Apple  | Food\Fruit\Apples 

私は

私は十字架を適用していたと思っていましたが、各親に対して複数の行が得られました。私は必要なものではない以下の表のようになります:

Category | Full path 
------------------------------------------ 
Drinks  | Drinks\Soda 
Soda  | Drinks\Soda 
Drinks  | Drinks\Juice 
Juice  | Drinks\Juice 

編集:これは私がこれまで持っているものです。

CREATE TABLE [dbo].[food_categories3](
    [id] [int] NOT NULL, 
    [category] [varchar](350) NULL) 

insert into food_categories3 
values 
(1,'Drinks\Soda'), 
(2,'Drinks\Juice\Fruit Juice\Apple Juice\Sugar Free'), 
(3,'Food\Fruit\Oranges'), 
(4,'Food\Fruit\Apples\Golden'), 
(5,'Food\Fruit\Apples\Red Delicious'), 
(6,'Food\Vegetables\Potatoes'), 
(7, 'Food\Meat'), 
(8,'Food') 

select * from food_categories3 

SELECT distinct X.category, 
    splitted.x.value('.', 'VARCHAR(100)') AS cat 
FROM (SELECT category, 
     CAST ('<M>' + REPLACE(category, '\', '</M><M>') + '</M>' AS XML) AS cat 
    FROM food_categories3) AS X CROSS APPLY cat.nodes ('/M') AS splitted(x) 
order by category 

はまた、私の実際のデータセットはフルーツのカテゴリに関するものではありません、これは私のデータが構成されているかの単純な例です。 。


編集2:どのように私はオレンジやリンゴの両方が、「フルーツ」の子であることを伝えることができるように私の主な質問は今、子供を挿入するとき、親行を追跡する方法、です。

+0

を見つけることがあまりにもハード、あなたがこれまでに作ったものな努力のコードを共有することはできますか? – ViKiNG

+0

まず、分割機能が必要です。ネット上に十分なものがあり、それを探してください。 –

+0

はい私は既にデータを分割し、問題を実行可能な例で更新しました。 – rememberthecant

答えて

2

再帰的なCTEを使用して、親子関係をソートする方法を説明します。

私は、あなたのクエリをソース(CTE_Source)を変更せずに使用して始めました。次の2つのCTEはデータの準備です。

最初のCTE - 見つかったカテゴリのすべてを削除して正しいパスを取得し、別個の値だけをフィルタリングします。

それはすべきではない。最後になりました計算されたパスとレベルの列を使用して、今、我々は(DENSE_RANK機能付)IDを割り当てると、すべての行のレベルを計算することができ、以前に作成したパスを使用して(スラッシュのカウント数) -

第二CTE再帰的に移動して、各カテゴリののParentID

WITH CTE_Source AS 
(
    SELECT distinct X.category, 
    splitted.x.value('.', 'VARCHAR(100)') AS cat 
FROM (SELECT category, 
     CAST ('<M>' + REPLACE(category, '\', '</M><M>') + '</M>' AS XML) AS cat 
    FROM food_categories3) AS X CROSS APPLY cat.nodes ('/M') AS splitted(x) 
) 
, CTE_Prep1 AS 
(
    SELECT DISTINCT 
    cat 
    , LEFT(category, PATINDEX ('%'+cat+'%', category) + LEN(cat) - 1) AS Path 
    FROM CTE_Source s 
) 
, CTE_Prep2 AS 
(
    SELECT 
    DENSE_RANK() OVER (ORDER BY Path) AS ID 
    , * 
    , LEN(Path) - LEN(REPLACE(Path, '\', '')) AS Level 
    FROM CTE_Prep1 
) 
, RCTE AS 
(
    SELECT *, CAST(NULL AS BIGINT) AS ParentID 
    FROM CTE_Prep2 
    WHERE Level = 0 

    UNION ALL 

    SELECT p.*, r.ID 
    FROM CTE_Prep2 p 
    INNER JOIN RCTE r ON p.Level = r.Level +1 AND p.Path LIKE r.Path + '%' 
) 
SELECT * FROM RCTE 
ORDER BY ID 

SQLFiddle DEMO

+0

それは動作します、あなたの時間をありがとう! – rememberthecant