2009-07-16 46 views
5

我在SQL中執行「樹狀」查詢(我們稱之爲?)有些麻煩。SQL「樹狀」查詢 - 大多數父組

看看我下面的圖表(表和列名在丹麥 - 我們對此深感抱歉):

DB diagram http://img197.imageshack.us/img197/8721/44060572.jpg 使用MSSQL Server 2005中,我們的目標是找到最父組(GRUPPE) ,爲每個客戶(昆德)。

每個組可以有許多父組和許多子組。

而且,我也想知道如何顯示該樹是這樣的:

 
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 2009-07-16 08:05:22

回答

4

我不能說比喬Celko更好。問題通常是建立的模型不適合構建層次結構,並且這些模型必須考慮層次結構的特徵。它太深了嗎?它太寬嗎?它是否狹窄和淺?

對於寬闊和淺層樹木來說,成功的關鍵之一就是在層次結構中有一個完整的路徑,就像Celko在第一個鏈接中提到的一樣。

+0

我已經看過那些文章。我沒有得到的是我如何將它應用到我的模式。 – 2009-07-16 08:04:14

+0

你可能無法說得比Celko好,但你肯定說它更好:) – 2009-07-16 08:10:24

1

在T-SQL,你可以寫一個while循環。未經測試:

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

我們使用SQL Server 2000和有擴大使用在SQL聯機叢書堆棧層次的一個例子,我已經寫了一些變種爲我們的ERP系統

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

據我瞭解,有2005年的SQL中使用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)