2009-07-16 6 views
5

SQLで「ツリー状」のクエリ(これは何と呼んでいますか?SQL "tree-like"クエリ - ほとんどの親グループ

私の下の図を見てみましょう(表と列の名前はデンマーク語である - そのことについて申し訳ありません):

DB diagram http://img197.imageshack.us/img197/8721/44060572.jpg MSSQL Server 2005を使用して、目標は、最も親グループ(グルッペ)を見つけることです、各顧客(Kunde)。

各グループには、多くの親グループと多数の子グループを含めることができます。

そして、私はまた、このようなツリーを表示する方法を知っていただきたいと思います:

 
Customer 1 
    - Parent group 1 
     - Child group 1 
     - ChildChild group n 
     - Child group n 
    - Parent group n 
     - ... 
     - ... 
Customer n 
    - ... 

もう一つの問題:

どのようにクエリはすべてのためのすべてのグループを取得するには見てないし顧客ですか?親子グループ。

+1

これを行うには、再帰的なクエリ(http://www.codeproject.com/KB/architecture/RoleBasedSecurity.aspxを参照)を使用することができます。 – Blixt

答えて

4

私はちょうどジョーCelkoよりもそれを言うことができません。問題は、通常、構築されたモデルが階層を構築するのに適しておらず、それらのモデルが階層の特性を考慮しなければならないということです。それはあまりにも深いですか?それは広すぎますか?それは狭くて浅いですか?

ワイドで浅いツリーで成功するための鍵の1つは、最初のリンクのCelkoのように、列の階層内に完全なパスを持つことです。 T-SQLで

+0

私はすでにそれらの記事を見てきました。私が得られないことは、スキーマにどのように適用できるかということです。 –

+0

Celkoよりも優れているとは言えないかもしれませんが、確かにそれはいいと思っています:) –

+0

あなたのスキーマを変更しなければ、良いパフォーマンスが得られないでしょう。 –

1

、あなたはwhileループを書くことができます。未テスト:

@group = <starting group> 
WHILE (EXISTS(SELECT * FROM Gruppe_Gruppe WHERE [email protected])) 
BEGIN 
    SELECT @group=ParentGruppeId FROM Gruppe_Gruppe WHERE [email protected] 
END 
+0

? @groupが親である場合はどうなりますか? –

+0

@groupにもう親グループがない場合、あなたはどういう意味ですか?ループは入力されず、結果は@groupです。これはあなたが望むものです。 –

+0

ああ。私の悪い。あなたはどのように各顧客のための最も親のグループを見つけるでしょうか?複数ある場合もあります。 –

1

私たちは、SQL Server 2000を使用して、SQL Books Onlineのスタックを使用して階層を展開した例があるが、私は私たちのERPシステムのためのバリアントの数を書かれている

http://support.microsoft.com/kb/248915

SQL 2005内でCTEを使用するネイティブメソッドがありますが、自分では使用していません。

5

CTEを使用して、「フルパス」カラムを即座に構築できます。

--DROP TABLE Gruppe, Kunde, Gruppe_Gruppe, Kunde_Gruppe 
CREATE TABLE Gruppe (
    Id     INT PRIMARY KEY 
    , Name    VARCHAR(100) 
    ) 
CREATE TABLE Kunde (
    Id     INT PRIMARY KEY 
    , Name    VARCHAR(100) 
    ) 
CREATE TABLE Gruppe_Gruppe (
    ParentGruppeId  INT 
    , ChildGruppeId  INT 
    ) 
CREATE TABLE Kunde_Gruppe (
    KundeId    INT 
    , GruppeId   INT 
    ) 

INSERT  Gruppe 
VALUES  (1, 'Group 1'), (2, 'Group 2'), (3, 'Group 3') 
      , (4, 'Sub-group A'), (5, 'Sub-group B'), (6, 'Sub-group C'), (7, 'Sub-group D') 

INSERT  Kunde 
VALUES  (1, 'Kunde 1'), (2, 'Kunde 2'), (3, 'Kunde 3') 

INSERT  Gruppe_Gruppe 
VALUES  (1, 4), (1, 5), (1, 7) 
      , (2, 6), (2, 7) 
      , (6, 1) 

INSERT  Kunde_Gruppe 
VALUES  (1, 1), (1, 2) 
      , (2, 3), (2, 4) 

;WITH  CTE 
AS   (
      SELECT  CONVERT(VARCHAR(1000), REPLACE(CONVERT(CHAR(5), k.Id), ' ', 'K')) AS TheKey 
         , k.Name  AS Name 
      FROM  Kunde k 

      UNION ALL 

      SELECT  CONVERT(VARCHAR(1000), REPLACE(CONVERT(CHAR(5), x.KundeId), ' ', 'K') 
          + REPLACE(CONVERT(CHAR(5), g.Id), ' ', 'G')) AS TheKey 
         , g.Name 
      FROM  Gruppe g 
      JOIN  Kunde_Gruppe x 
      ON   g.Id = x.GruppeId 

      UNION ALL 

      SELECT  CONVERT(VARCHAR(1000), p.TheKey + REPLACE(CONVERT(CHAR(5), g.Id), ' ', 'G')) AS TheKey 
         , g.Name 
      FROM  Gruppe g 
      JOIN  Gruppe_Gruppe x 
      ON   g.Id = x.ChildGruppeId 
      JOIN  CTE p 
      ON   REPLACE(CONVERT(CHAR(5), x.ParentGruppeId), ' ', 'G') = RIGHT(p.TheKey, 5) 
      WHERE  LEN(p.TheKey) < 32 * 5 
      ) 
SELECT  * 
      , LEN(TheKey)/5 AS Level 
FROM  CTE c 
ORDER BY c.TheKey 

多くの読取りと稀な修正がある場合、パフォーマンスは最適ではない可能性があります。

3

私は、顧客ごとにすべてのグループをリストするという問題を解決するソリューションを考え出しました。親子グループ。

あなたはどう思いますか?

どのようにこのような何かについて
 
WITH GroupTree 
AS 
(
    SELECT kg.KundeId, g.Id GruppeId 
    FROM ActiveDirectory.Gruppe g 
    INNER JOIN ActiveDirectory.Kunde_Gruppe kg ON g.Id = kg.GruppeId 
    AND (EXISTS (SELECT * FROM ActiveDirectory.Gruppe_Gruppe WHERE ParentGruppeId = g.Id) 
    OR NOT EXISTS (SELECT * FROM ActiveDirectory.Gruppe_Gruppe WHERE ParentGruppeId = g.Id)) 

    UNION ALL 

    SELECT GroupTree.KundeId, gg.ChildGruppeId 
    FROM ActiveDirectory.Gruppe_Gruppe gg 
    INNER JOIN GroupTree ON gg.ParentGruppeId = GroupTree.GruppeId 
) 
SELECT KundeId, GruppeId 
FROM GroupTree 

OPTION (MAXRECURSION 32767) 
2

:「トップ祖先」私はこのタイプのデータのための共通の名前は「階層的」であり、あなたがしたいと考えてい

DECLARE @Customer TABLE(
     CustomerID INT IDENTITY(1,1), 
     CustomerName VARCHAR(MAX) 
) 

INSERT INTO @Customer SELECT 'Customer1' 
INSERT INTO @Customer SELECT 'Customer2' 
INSERT INTO @Customer SELECT 'Customer3' 

DECLARE @CustomerTreeStructure TABLE(
     CustomerID INT, 
     TreeItemID INT 
) 

INSERT INTO @CustomerTreeStructure (CustomerID,TreeItemID) SELECT 1, 1 
INSERT INTO @CustomerTreeStructure (CustomerID,TreeItemID) SELECT 2, 12 
INSERT INTO @CustomerTreeStructure (CustomerID,TreeItemID) SELECT 3, 1 
INSERT INTO @CustomerTreeStructure (CustomerID,TreeItemID) SELECT 3, 12 

DECLARE @TreeStructure TABLE(
     TreeItemID INT IDENTITY(1,1), 
     TreeItemName VARCHAR(MAX), 
     TreeParentID INT 
) 

INSERT INTO @TreeStructure (TreeItemName,TreeParentID) SELECT '001', NULL 
INSERT INTO @TreeStructure (TreeItemName,TreeParentID) SELECT '001.001', 1 
INSERT INTO @TreeStructure (TreeItemName,TreeParentID) SELECT '001.001.001', 2 
INSERT INTO @TreeStructure (TreeItemName,TreeParentID) SELECT '001.001.002', 2 
INSERT INTO @TreeStructure (TreeItemName,TreeParentID) SELECT '001.001.003', 2 
INSERT INTO @TreeStructure (TreeItemName,TreeParentID) SELECT '001.002', 1 
INSERT INTO @TreeStructure (TreeItemName,TreeParentID) SELECT '001.003', 1 
INSERT INTO @TreeStructure (TreeItemName,TreeParentID) SELECT '001.003.001', 7 
INSERT INTO @TreeStructure (TreeItemName,TreeParentID) SELECT '001.001.002.001', 4 
INSERT INTO @TreeStructure (TreeItemName,TreeParentID) SELECT '001.001.002.002', 4 
INSERT INTO @TreeStructure (TreeItemName,TreeParentID) SELECT '001.001.002.003', 4 

INSERT INTO @TreeStructure (TreeItemName,TreeParentID) SELECT '002', NULL 
INSERT INTO @TreeStructure (TreeItemName,TreeParentID) SELECT '002.001', 12 
INSERT INTO @TreeStructure (TreeItemName,TreeParentID) SELECT '002.001.001', 13 
INSERT INTO @TreeStructure (TreeItemName,TreeParentID) SELECT '002.001.002', 13 

;WITH Structure AS (
    SELECT TreeItemID, 
      TreeItemName, 
      TreeParentID, 
      REPLICATE('0',5 - LEN(CAST(TreeItemID AS VARCHAR(MAX)))) + CAST(TreeItemID AS VARCHAR(MAX)) + '\\' TreePath 
    FROM @TreeStructure ts 
    WHERE ts.TreeParentID IS NULL 
    UNION ALL 
    SELECT ts.*, 
      s.TreePath + REPLICATE('0',5 - LEN(CAST(ts.TreeItemID AS VARCHAR(5)))) + CAST(ts.TreeItemID AS VARCHAR(5)) + '\\' TreePath 
    FROM @TreeStructure ts INNER JOIN 
      Structure s ON ts.TreeParentID = s.TreeItemID 
) 

SELECT c.CustomerName, 
     Children.TreeItemName, 
     Children.TreePath 
FROM @Customer c INNER JOIN 
     @CustomerTreeStructure cts ON c.CustomerID = cts.CustomerID INNER JOIN 
     Structure s ON cts.TreeItemID = s.TreeItemID INNER JOIN 
     (
      SELECT * 
      FROM Structure 
     ) Children ON Children.TreePath LIKE s.TreePath +'%' 
ORDER BY 1,3 
OPTION (MAXRECURSION 0) 
関連する問題