用于显示分层数据的SQL Server查询或工具

时间:2010-07-30 12:59:46

标签: sql-server-2008 hierarchical-data

我们有一个通用的组织表结构,认为它是树或金字塔层次结构。我们基本上有多个想要展示的“树”。在一家公司,一家为另一家公司。

有谁知道显示这些数据的好方法? SQL Query会很好,怀疑它是可能的,但我不反对使用一些OTS工具(最好是免费的)。我还想避免某种类型的报道。我不需要实际的解决方案,只需知道是否可能。所以,如果你说SQL,如果你能给我一个2表的示例,显示一个假,我会很高兴。

结构非常通用

alt text

每个表都通过代理键CompanyID,CompanyGroupID等链接

有关我们如何显示/查询此数据的任何建议?最后的办法是编写一个快速的C#Windows应用程序......

我们希望以树形式看到它:

--                      1-Company
--                     /        \
--             CompanyGroupA   CompanyGroupB
--            /       \              \
--  CompanyStoreA1 CompanyStoreA1 CompanyStoreB
--    /      \            /    \
--Employee   A            B     C   

这里试图取悦群众是一个填充查询的示例测试脚本。

DECLARE @Company table (id int, name varchar(40) )
INSERT @Company VALUES (1,'Living Things' )  
INSERT @Company VALUES (2,'Boring Company' )  


DECLARE @CompanyGroup table (id int, name varchar(40), CompanyID int)
INSERT @CompanyGroup VALUES (1,'Pets',1 ) 
INSERT @CompanyGroup VALUES (2,'Humans',1 ) 
INSERT @CompanyGroup VALUES (3,'Electronics',2 ) 
INSERT @CompanyGroup VALUES (4,'Food',2 ) 


DECLARE @CompanyStore table (id int, name varchar(40), CompanyGroupID int)
INSERT @CompanyStore VALUES (1,'PetsStoreA',1 ) 
INSERT @CompanyStore VALUES (2,'PetsStoreB',1 ) 
INSERT @CompanyStore VALUES (3,'PetsStoreC',1 ) 
INSERT @CompanyStore VALUES (4,'PetsStoreD', 1) 
INSERT @CompanyStore VALUES (5,'HumansStore',2 ) 
INSERT @CompanyStore VALUES (6,'FoodStore',3 ) 

最终解决方案非常棒我修改了usp_DrawTree以接受varchar vs int,因为我必须使我的查询ID唯一。然后我做了一个select / union all并构建了父子关系。

select * into #TreeData from (
  select ID='C' + cast(id as varchar(10)),
       ParentID=null,
       DataForBox=name + '(' + cast(id as varchar(10)) + ')',
       ExtraInfo='', 
       SortColumn=name
  from Company c 
 )
union all (
  select ID='CG' + cast(id as varchar(10)),
       ParentID=cg.CompanyID ,
       DataForBox=name + '(' + cast(id as varchar(10)) + ')',
       ExtraInfo='', 
       SortColumn=name
  from CompanyGroup cg join Company c on c.ID=cg.CompanyID 
  ) 
//union all rest of hierarchy
)

4 个答案:

答案 0 :(得分:3)

布拉德舒尔茨以usp_DrawTree的形式救援。

alt text http://i36.tinypic.com/2zqssxc.png

答案 1 :(得分:2)

您没有提供任何表结构,因此这里是一个递归CTE处理树结构的示例:

--go through a nested table supervisor - user table and display the chain
DECLARE @Contacts table (id varchar(6), first_name varchar(10), reports_to_id varchar(6))
INSERT @Contacts VALUES ('1','Jerome', NULL )  -- tree is as follows:
INSERT @Contacts VALUES ('2','Joe'   ,'1')     --                      1-Jerome
INSERT @Contacts VALUES ('3','Paul'  ,'2')     --                     /        \
INSERT @Contacts VALUES ('4','Jack'  ,'3')     --              2-Joe           9-Bill
INSERT @Contacts VALUES ('5','Daniel','3')     --            /       \              \
INSERT @Contacts VALUES ('6','David' ,'2')     --     3-Paul          6-David       10-Sam
INSERT @Contacts VALUES ('7','Ian'   ,'6')     --    /      \            /    \
INSERT @Contacts VALUES ('8','Helen' ,'6')     -- 4-Jack  5-Daniel   7-Ian    8-Helen
INSERT @Contacts VALUES ('9','Bill ' ,'1')     --
INSERT @Contacts VALUES ('10','Sam'  ,'9')     --

DECLARE @Root_id  char(4)

--get complete tree---------------------------------------------------
SET @Root_id=null
PRINT '@Root_id='+COALESCE(''''+@Root_id+'''','null')
;WITH StaffTree AS
(
    SELECT 
        c.id, c.first_name, c.reports_to_id, c.reports_to_id as Manager_id, cc.first_name AS Manager_first_name, 1 AS LevelOf
        FROM @Contacts                  c
            LEFT OUTER JOIN @Contacts  cc ON c.reports_to_id=cc.id
        WHERE c.id=@Root_id OR (@Root_id IS NULL AND c.reports_to_id IS NULL)
    UNION ALL
        SELECT 
            s.id, s.first_name, s.reports_to_id, t.id, t.first_name, t.LevelOf+1
        FROM StaffTree            t
            INNER JOIN @Contacts  s ON t.id=s.reports_to_id
    WHERE s.reports_to_id=@Root_id OR @Root_id IS NULL OR t.LevelOf>1
)
SELECT * FROM StaffTree


--get all below 2---------------------------------------------------
SET @Root_id=2
PRINT '@Root_id='+COALESCE(''''+@Root_id+'''','null')
;WITH StaffTree AS
(
    SELECT 
        c.id, c.first_name, c.reports_to_id, c.reports_to_id as Manager_id, cc.first_name AS Manager_first_name, 1 AS LevelOf
        FROM @Contacts                  c
            LEFT OUTER JOIN @Contacts  cc ON c.reports_to_id=cc.id
        WHERE c.id=@Root_id OR (@Root_id IS NULL AND c.reports_to_id IS NULL)
    UNION ALL
        SELECT 
            s.id, s.first_name, s.reports_to_id, t.id, t.first_name, t.LevelOf+1
        FROM StaffTree            t
            INNER JOIN @Contacts  s ON t.id=s.reports_to_id
    WHERE s.reports_to_id=@Root_id OR @Root_id IS NULL OR t.LevelOf>1
)
SELECT * FROM StaffTree

--get all below 6---------------------------------------------------
SET @Root_id=6
PRINT '@Root_id='+COALESCE(''''+@Root_id+'''','null')
;WITH StaffTree AS
(
    SELECT 
        c.id, c.first_name, c.reports_to_id, c.reports_to_id as Manager_id, cc.first_name AS Manager_first_name, 1 AS LevelOf
        FROM @Contacts                  c
            LEFT OUTER JOIN @Contacts  cc ON c.reports_to_id=cc.id
        WHERE c.id=@Root_id OR (@Root_id IS NULL AND c.reports_to_id IS NULL)
    UNION ALL
        SELECT 
            s.id, s.first_name, s.reports_to_id, t.id, t.first_name, t.LevelOf+1
        FROM StaffTree            t
            INNER JOIN @Contacts  s ON t.id=s.reports_to_id
    WHERE s.reports_to_id=@Root_id OR @Root_id IS NULL OR t.LevelOf>1
)
SELECT * FROM StaffTree

输出:

@Root_id=null
id     first_name reports_to_id Manager_id Manager_first_name LevelOf
------ ---------- ------------- ---------- ------------------ -----------
1      Jerome     NULL          NULL       NULL               1
2      Joe        1             1          Jerome             2
9      Bill       1             1          Jerome             2
10     Sam        9             9          Bill               3
3      Paul       2             2          Joe                3
6      David      2             2          Joe                3
7      Ian        6             6          David              4
8      Helen      6             6          David              4
4      Jack       3             3          Paul               4
5      Daniel     3             3          Paul               4

(10 row(s) affected)

@Root_id='2   '
id     first_name reports_to_id Manager_id Manager_first_name LevelOf
------ ---------- ------------- ---------- ------------------ -----------
2      Joe        1             1          Jerome             1
3      Paul       2             2          Joe                2
6      David      2             2          Joe                2
7      Ian        6             6          David              3
8      Helen      6             6          David              3
4      Jack       3             3          Paul               3
5      Daniel     3             3          Paul               3

(7 row(s) affected)

@Root_id='6   '
id     first_name reports_to_id Manager_id Manager_first_name LevelOf
------ ---------- ------------- ---------- ------------------ -----------
6      David      2             2          Joe                1
7      Ian        6             6          David              2
8      Helen      6             6          David              2

(3 row(s) affected)

编辑基于OP的给定表格和数据:

尝试这样的事情:

SET NOCOUNT ON
DECLARE @Company table (id int, name varchar(40) )
INSERT @Company VALUES (1,'Living Things' )  
INSERT @Company VALUES (2,'Boring Company' )  

DECLARE @CompanyGroup table (id int, name varchar(40), CompanyID int)
INSERT @CompanyGroup VALUES (1,'Pets'        ,1 ) 
INSERT @CompanyGroup VALUES (2,'Humans'      ,1 ) 
INSERT @CompanyGroup VALUES (3,'Electronics' ,2 ) 
INSERT @CompanyGroup VALUES (4,'Food'        ,2 ) 

DECLARE @CompanyStore table (id int, name varchar(40), CompanyGroupID int)
INSERT @CompanyStore VALUES (1,'PetsStoreA'   ,1 ) 
INSERT @CompanyStore VALUES (2,'PetsStoreB'   ,1 ) 
INSERT @CompanyStore VALUES (3,'PetsStoreC'   ,1 ) 
INSERT @CompanyStore VALUES (4,'PetsStoreD'   ,1) 
INSERT @CompanyStore VALUES (5,'HumansStore'  ,2 ) 
INSERT @CompanyStore VALUES (6,'FoodStore'    ,3 ) 

--not provided by the OP, so I made it up
DECLARE @CompanyEmployees table (id int, name varchar(10), reports_to_id int, CompanyStoreID int)
INSERT @CompanyEmployees VALUES (1,'Jerome', NULL ,1)  -- tree is as follows:
INSERT @CompanyEmployees VALUES (2,'Joe'   ,1     ,1)     --                      PetsStoreA             PetsStoreB         PetStoreC          FoodStore
INSERT @CompanyEmployees VALUES (3,'Paul'  ,2     ,1)     --                      1-Jerome                 11-Alan           14-Ben              18-apple
INSERT @CompanyEmployees VALUES (4,'Jack'  ,3     ,1)     --                     /        \                /      \           /                  /     \
INSERT @CompanyEmployees VALUES (5,'Daniel',3     ,1)     --              2-Joe           9-Bill         12-Ally  13-Abby    15-Bill         19-pear   20-grape
INSERT @CompanyEmployees VALUES (6,'David' ,2     ,1)     --            /       \              \                             /      \                    /
INSERT @CompanyEmployees VALUES (7,'Ian'   ,6     ,1)     --     3-Paul          6-David       10-Sam                     16-Bjorn  17-Benny           21-rasin
INSERT @CompanyEmployees VALUES (8,'Helen' ,6     ,1)     --    /      \            /    \
INSERT @CompanyEmployees VALUES (9,'Bill ' ,1     ,1)     -- 4-Jack  5-Daniel   7-Ian    8-Helen
INSERT @CompanyEmployees VALUES (10,'Sam'  ,9     ,1)     --
INSERT @CompanyEmployees VALUES (11,'Alan' ,NULL  ,2)     --to see all trees, scroll--->>
INSERT @CompanyEmployees VALUES (12,'Ally' ,11    ,2)     --
INSERT @CompanyEmployees VALUES (13,'Abby' ,11    ,2)     --
INSERT @CompanyEmployees VALUES (14,'Ben'  ,NULL  ,3)     --     
INSERT @CompanyEmployees VALUES (15,'Bill' ,14    ,3)     --
INSERT @CompanyEmployees VALUES (16,'Bjorn',15    ,3)     --
INSERT @CompanyEmployees VALUES (17,'Benny',15    ,3)     --
INSERT @CompanyEmployees VALUES (18,'apple',NULL  ,6)     --
INSERT @CompanyEmployees VALUES (19,'pear' ,18    ,6)     --
INSERT @CompanyEmployees VALUES (20,'grape',18    ,6)     --
INSERT @CompanyEmployees VALUES (21,'rasin',21    ,6)     --
SET NOCOUNT OFF

;WITH StaffTree AS
(
    SELECT 
        c.id, c.name, c.reports_to_id, c.reports_to_id as Manager_id, cc.name AS Manager_name, 1 AS LevelOf, c.CompanyStoreID
        FROM @CompanyEmployees                c
            LEFT OUTER JOIN @CompanyEmployees cc ON c.reports_to_id=cc.id
        WHERE c.reports_to_id IS NULL
    UNION ALL
        SELECT 
            s.id, s.name, s.reports_to_id, t.id, t.name, t.LevelOf+1, s.CompanyStoreID
        FROM StaffTree                    t
            INNER JOIN @CompanyEmployees  s ON t.id=s.reports_to_id
)
SELECT
    c.id AS CompanyID, c.name AS CompanyName
        ,g.id AS CompanyGroupID, g.name AS CompanyName
        ,s.id AS CompanyStoreID, s.name AS CompanyStoreName
        ,t.id AS EmployeeID, t.name as EmployeeName, t.Manager_id, t.Manager_name, t.LevelOf
    FROM @Company                c
        LEFT JOIN @CompanyGroup  g ON c.id=g.CompanyID
        LEFT JOIN @CompanyStore  s ON g.id=s.CompanyGroupID
        LEFT JOIN StaffTree      t ON s.id=t.CompanyStoreID
    ORDER BY c.name,g.name,s.name,s.ID,t.LevelOf,t.name

输出:

CompanyID CompanyName    CompanyGroupID CompanyName CompanyStoreID CompanyStoreName EmployeeID  EmployeeName Manager_id  Manager_name LevelOf
--------- -------------- -------------- ----------- -------------- ---------------- ----------- ------------ ----------- ------------ -------
2         Boring Company 3              Electronics 6              FoodStore        18          apple        NULL        NULL         1
2         Boring Company 3              Electronics 6              FoodStore        20          grape        18          apple        2
2         Boring Company 3              Electronics 6              FoodStore        19          pear         18          apple        2
2         Boring Company 4              Food        NULL           NULL             NULL        NULL         NULL        NULL         NULL
1         Living Things  2              Humans      5              HumansStore      NULL        NULL         NULL        NULL         NULL
1         Living Things  1              Pets        1              PetsStoreA       1           Jerome       NULL        NULL         1
1         Living Things  1              Pets        1              PetsStoreA       9           Bill         1           Jerome       2
1         Living Things  1              Pets        1              PetsStoreA       2           Joe          1           Jerome       2
1         Living Things  1              Pets        1              PetsStoreA       6           David        2           Joe          3
1         Living Things  1              Pets        1              PetsStoreA       3           Paul         2           Joe          3
1         Living Things  1              Pets        1              PetsStoreA       10          Sam          9           Bill         3
1         Living Things  1              Pets        1              PetsStoreA       5           Daniel       3           Paul         4
1         Living Things  1              Pets        1              PetsStoreA       8           Helen        6           David        4
1         Living Things  1              Pets        1              PetsStoreA       7           Ian          6           David        4
1         Living Things  1              Pets        1              PetsStoreA       4           Jack         3           Paul         4
1         Living Things  1              Pets        2              PetsStoreB       11          Alan         NULL        NULL         1
1         Living Things  1              Pets        2              PetsStoreB       13          Abby         11          Alan         2
1         Living Things  1              Pets        2              PetsStoreB       12          Ally         11          Alan         2
1         Living Things  1              Pets        3              PetsStoreC       14          Ben          NULL        NULL         1
1         Living Things  1              Pets        3              PetsStoreC       15          Bill         14          Ben          2
1         Living Things  1              Pets        3              PetsStoreC       17          Benny        15          Bill         3
1         Living Things  1              Pets        3              PetsStoreC       16          Bjorn        15          Bill         3
1         Living Things  1              Pets        4              PetsStoreD       NULL        NULL         NULL        NULL         NULL

(23 row(s) affected)
在OP的编辑声明We would like to see it in tree form之后

编辑

问题标记为sql-server-2008hierarchical-data,并且OP希望执行复杂的格式化以显示数据。但是,这种类型的处理和显示不是TSQL的领域,并且是应用程序语言应该处理和格式化SQL查询提供的平面数据的一个非常明确的示例。我提供了一个可以由应用程序用来构建可视树显示的查询。另请注意,简单的树示例(每个父项不超过两个子项)可能不太现实,当单个父项存在多个子项时,显示将变得难以构建且不悦目。

答案 2 :(得分:0)

您可以使用报告服务将其显示回SQL 2008;如果你很幸运,它可能已经设置 - 如果不是很容易做到这一点。您可以在报表服务中使用功能,以便让用户可以非常轻松地根据需要钻取数据。

在查询方面;树长大还是固定?用于从数据库中获取数据的SQL查询非常简单。

Select 
    CompanyName,
    CompanyGroupName,
    CompanyStoreName,
    CompanyEmployeeForename,
    CompanyEmployeeSurname

From tblCompanies com
left outer join tblCompanyGroups cg
on com.CompanyGroupID = cg.CompanyGroupID

Left outer Join tblCompanyStore cs
on com.CompanyID = cs.CompanyID

left outer join tblCompanyEmployees ce
on com.CompanyID = ce.CompanyName

答案 3 :(得分:0)

我相信SQL Server 2008提供了一种新的数据类型来帮助解决这个问题。以下是我认为有用的链接 - http://msdn.microsoft.com/en-us/magazine/cc794278.aspx。我没有在任何评论中看到它,所以希望这有帮助。