2013-06-06 8 views
7

私はツリー構造と、それに続くSQL Serverデータベースの顧客カテゴリの代入テーブルを持っています。SQLサーバーのツリー構造内のサブツリーの下にあるすべてのリーフノードを見つけよう

CustomerCategory (CategoryID, ParentId) 
CustomerInCategory(CustomerID, CategoryID) 

CustomerCategoryに割り当てられている顧客がある場合、その顧客に別のサブカテゴリを追加することはできません。そのため、顧客は各サブツリーの最下位レベルにのみ追加することができます。他の意味では、このクエリの結果は

SELECT * FROM `CustomerCategory` WHERE `CategoryId` NOT IN 
(SELECT DISTINCT `parentid` FROM `CustomerCategory` WHERE `parentid` IS NOT NULL) 

となります。他のことは、このツリーには異なるレベルのサブツリーがあるかもしれませんし、とにかくレベルの数を制限したくないということですが、ユーザーは10レベルを超える必要はありません。

CategoryID------ParentID---------------Name 
1    NULL     All Customers 
2    1      Domestic 
3    1      International 
4    2      Independent Retailers 
5    2      Chain Retailers 
6    2      Whole Sellers 
7    5      A-Mart 
8    5      B-Mart 
9    4      Grocery Stores 
10    4      Restaurants 
11    4      Cafes 

CustomerID---------CustomerName----------Category 
1     Int.Customer#1    3 
2     Int.Customer#2    3 
3     A-Mart.Branch#1    7 
4     A-Mart.Branch#2    7 
5     B-Mart.Branch#1    8 
6     B-Mart.Branch#2    8 
7     Grocery#1     9 
8     Grocery#2     9 
9     Grocery#3     9 
10     Restaurant#1     10 
11     Restaurant#2     10 
12     Cafe#1      11 
13     Wholeseller#1    6 
14     Wholeseller#2    6 

私の要件は、「カテゴリのノードを指定すると、その下のノードに接続されたすべての顧客を返す」というものです。

sqlを使ってどうすればいいですか?

明らかにこれはコード内の再帰呼び出しで行うことができますが、t-sqlで(ストアドプロシージャを何度も呼び出すことなく、またはテキストベースの検索を使用しないで)どのように行うことができますか?

この問題を解決するためにCTEを使用できますか?

私はこれは必ずしもこのような結果をレイアウトするのは良いアイデアではありません心の中で

CustomerID--------Customer Name----------------CategoryId----------CAtegoryName 

12    Cafe#1      11     Cafes 
12    Cafe#1      4     IndependentRetailers 
12    Cafe#1      2     Demoestic 
12    Cafe#1      1     AllCustomers 
. 
. 
. 
4     A-Mart.Branch#2    7     A-Mart 
4     A-Mart.Branch#2    5     Chain Retailers 
4     A-Mart.Branch#2    2     Domestic 
4     A-Mart.Branch#2    1     All Customers 
. 
. 
. 
14     Wholeseller#2    6     WholeSellers 
14     Wholeseller#2    2     Domestic 
14     Wholeseller#2    1     All Customers 

をこのような何かの結果セットを持って、これは、必要とされない可能性があります何かをあまりにも多くのスペースを消費することになります、しかし、そのような結果セット内での検索は非常に高速である。私は以下のすべての顧客が区分= 2と言う検索したい場合は、私は単純に、データモデルを改善するための任意の提案が超歓迎される

SELECT * FROM resultset where category ID = 2 

を照会します!この問題を解決するのに役立ちます。

もう一度、私はこの結果セットに固執していません。 「カテゴリにノードがあれば、その下のノードに接続されているすべての顧客を返す」という問題を解決するその他の提案がよく受け入れられます。

答えて

9

あなたは再帰的にすべての親子関係を含むテーブルを構築するためにCTEを使用して(区分5の下の私の例では、everyting)のみ必要なサブツリーを取得するためにwhere句を使用することができます。

WITH CategorySubTree AS (
    SELECT cc.CategoryId as SubTreeRoot, 
      cc.CategoryId 
      FROM CustomerCategory cc 
UNION ALL 
    SELECT cst.SubTreeRoot, cc.CategoryId 
     FROM CustomerCategory cc 
     INNER JOIN CategorySubTree cst ON cst.CategoryId = cc.parentId 
) 
SELECT cst.CategoryId 
FROM CategorySubTree cst 
WHERE cst.SubTreeRoot = 5 

あなたはサブツリー内のカテゴリのノードにリンクされている顧客を取得するには、たとえば、あなたが必要とするものは何でも追加するには、このクエリを変更することができます。

WITH CategorySubTree AS (
    SELECT cc.CategoryId as SubTreeRoot, 
      cc.CategoryId 
      FROM CustomerCategory cc 
UNION ALL 
    SELECT cst.SubTreeRoot, cc.CategoryId 
     FROM CustomerCategory cc 
     INNER JOIN CategorySubTree cst ON cst.CategoryId = cc.parentId 
) 
SELECT cst.CategoryId,cic.CustomerId 
FROM CategorySubTree cst 
     INNER JOIN CustomerInCategory cic ON cic.CategoryId = cst.CategoryId 
WHERE cst.SubTreeRoot = 5 

をそしてもちろん、あなたがラベルやその他の必要な情報を取得するために、さらにテーブルを結合することができます。

+0

非常に賢い...非常に賢い...ありがとう。 – user1155391

+0

MS SQLサーバーでそれを行う方法はありますか? – sajushko

関連する問題