2009-07-06 3 views
1

私はカテゴリのテーブルを持っています。各カテゴリは、ルートレベルのカテゴリ(親はNULL)か、ルートレベルのカテゴリである親を持つことができます。ネストのレベルは複数にすることはできません。SQL - 複数の条件による注文

私は、次の表の構造を持っている:

Categories Table Structure http://img16.imageshack.us/img16/8569/categoriesi.png

は、私は次の出力を生成するクエリを使用することができますどのような方法があります:

 
Free Stuff 
Hardware 
Movies 
CatA 
CatB 
CatC 
Software 
Apples 
CatD 
CatE 

だから、結果はトップレベル順に並んでいカテゴリを選択した後、各カテゴリのサブカテゴリがリストされます。

実際に親または名前で注文するのではなく、2つのコンボで注文しています。私はSQL Serverを使用しています。

+1

はもしかしてその: 無料で譲り AA2 ハードウェア 作品 CATA 等... ? –

答えて

1

[OK]を、ここで私達は行く:

with foo as 
(
select 1 as id, null as parent, 'CatA' as cat from dual 
union select 2, null, 'CatB' from dual 
union select 3, null, 'CatC' from dual 
union select 4, 1, 'SubCatA_1' from dual 
union select 5, 1, 'SubCatA_2' from dual 
union select 6, 2, 'SubCatB_1' from dual 
union select 7, 2, 'SubCatB_2' from dual 
) 
select child.cat 
from foo parent right outer join foo child on parent.id = child.parent 
order by case when parent.id is not null then parent.cat else child.cat end, 
     case when parent.id is not null then 1 else 0 end 

結果:

CatA 
SubCatA_1 
SubCatA_2 
CatB 
SubCatB_1 
SubCatB_2 
CatC 

編集 - ソリューションの変更がによってバンの注文から鼓舞します!そう簡単に。

+0

この解決方法は、ツリーに別のレベルを追加するとすぐに解除されます。私。 union select 8,7、 'SubCatB_2.1'をデュアルから追加すると、結果にCatCの下にSubCatB_2.1が表示されます。 –

+0

"ネストのレベルは複数ありません。"非常に大きなデザインの非常に大きなソリューションについて議論することは興味がありません。 –

+0

実際に動作するように見えたのは少数のものの1つで、比較的簡単にそれを取り巻くこともできます:) ありがとうScirpi0。 – Echilon

1

あなたの質問は完全には分かっていませんが、PARTITION BYのように聞こえるかもしれません。 PARTITION BY hereには入門記事があります。

4

階層を平坦化して並べ替えることを検討しているようですが、この注文を取得する最も安い方法は、完全なパスを持つテーブルに追加の列を格納することです。例えばので

 
Name   | Full Path 
Free Stuff  | Free Stuff 
aa2    | Free Stuff - aa2    

あなたは完全なパスを格納したら、あなたはそれを注文することができます。

深度が1つのみの場合は、単一のサブクエリ(およびその順序)でこのエフェクトの文字列を自動的に生成できますが、この解決法は深くなると簡単には機能しません。

もう1つの選択肢は、これを一時テーブルに全部移動し、必要に応じて完全なパスを計算することです。しかし、それはかなり高価です。

2

テーブル自体を見て、親の名前順、子の名前順にすることができます。

select categories.Name AS DisplayName 
from  categories LEFT OUTER JOIN 
     categories AS parentTable ON categories.Parent = parentTable.ID 
order by parentTable.Name, DisplayName 
+0

これは、最大2レベルの階層でのみ機能します。 –

+0

LEFT JOINを右に変更すると、これがうまくいくと言ってポストしようとしていました。 – Echilon

1

ここでは、再帰的な共通テーブル式を使用した完全な実例があります。

DECLARE @categories TABLE 
(
    ID INT NOT NULL, 
    [Name] VARCHAR(50), 
    Parent INT NULL 
); 

INSERT INTO @categories VALUES (4, 'Free Stuff', NULL); 
INSERT INTO @categories VALUES (1, 'Hardware', NULL); 
INSERT INTO @categories VALUES (3, 'Movies', NULL); 
INSERT INTO @categories VALUES (2, 'Software', NULL); 
INSERT INTO @categories VALUES (10, 'a', 0); 
INSERT INTO @categories VALUES (12, 'apples', 2); 
INSERT INTO @categories VALUES (8, 'catD', 2); 
INSERT INTO @categories VALUES (9, 'catE', 2); 
INSERT INTO @categories VALUES (5, 'catA', 3); 
INSERT INTO @categories VALUES (6, 'catB', 3); 
INSERT INTO @categories VALUES (7, 'catC', 3); 
INSERT INTO @categories VALUES (11, 'aa2', 4); 

WITH categories(ID, Name, Parent, HierarchicalName) 
AS 
(
    SELECT 
     c.ID 
     , c.[Name] 
     , c.Parent 
     , CAST(c.[Name] AS VARCHAR(200)) AS HierarchicalName 
    FROM @categories c 
    WHERE c.Parent IS NULL 

    UNION ALL 

    SELECT 
     c.ID 
     , c.[Name] 
     , c.Parent 
     , CAST(pc.HierarchicalName + c.[Name] AS VARCHAR(200)) 
    FROM @categories c 
    JOIN categories pc ON c.Parent = pc.ID 
) 
SELECT c.* 
FROM categories c 
ORDER BY c.HierarchicalName 
1
SELECT 
    ID, 
    Name, 
    Parent, 
    RIGHT(
    '000000000000000' + 
    CASE WHEN Parent IS NULL 
    THEN CONVERT(VARCHAR, Id) 
    ELSE CONVERT(VARCHAR, Parent) 
    END, 15 
) 
    + '_' + CASE WHEN Parent IS NULL THEN '0' ELSE '1' END 
    + '_' + Name 
FROM 
    categories 
ORDER BY 
    4 

長いパディングは、SQL ServerのINTデータ型は2,147,483,647を通じて2147483648から行くという事実を考慮するためです。

を直接使用する必要はありません。ORDER BYを直接入力することができます。それは並べ替えているものを表示することでした。

この式ではインデックスを使用できないことに注意してください。これは、大きなテーブルのソートが遅くなることを意味します。