【问题标题】:SQL Server :Recursive CTE? Creating Report From an Organisation StructureSQL Server:递归 CTE?从组织结构创建报告
【发布时间】:2014-05-12 08:48:40
【问题描述】:

我希望有人可以帮助我。我想要一份包含组织结构计算的报告。

CREATE TABLE Organistation
  (
    KeySubCompany NUMERIC(12, 0) ,
    O1 VARCHAR(255) ,
    O2 VARCHAR(255) ,
    O3 VARCHAR(255) ,
    O4 VARCHAR(255) ,
    O5 VARCHAR(255) ,
    O6 VARCHAR(255) ,
    O7 VARCHAR(255) ,
    O8 VARCHAR(255) ,
    O9 VARCHAR(255) ,
    O10 VARCHAR(255) ,
    O11 VARCHAR(255) ,
    O12 VARCHAR(255)
  )

INSERT    INTO dbo.Organistation
          ( KeySubCompany, O1, O2, O3, O4, O5, O6, O7, O8, O9, O10, O11, O12 )
VALUES    ( 1, 'World', 'Europe', 'Germany', 'Berlin', NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL ),
          ( 2, 'World', 'Europe', 'Germany', 'Hamburg', NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL ),
          ( 3, 'World', 'Europe', 'Italy', 'Rom', NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL ),
          ( 4, 'World', 'Europe', 'Italy', 'Neapel', NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL ),
          ( 5, 'World', 'Europe', 'Germany', 'Dresden', NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL ),
          ( 6, 'World', 'North America', 'Canada', NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL ),
          ( 7, 'World', 'North America', 'USA', 'New York', NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL )        


CREATE TABLE COMPANY
  (
    KeyCompany NUMERIC(12, 0) ,
    NAME VARCHAR(255) ,
    viewdepth INTEGER
  )


INSERT    INTO dbo.COMPANY
          ( KeyCompany, NAME, viewdepth )
VALUES    ( 1, 'Main', 2 )

CREATE TABLE SUBCOMPANY
  (
    KeySubCompany NUMERIC(12, 0) ,
    KeyCompany NUMERIC(12, 0) ,
    NameSubCompany VARCHAR(255)
  )


INSERT    INTO dbo.SUBCOMPANY
          ( KeySubCompany, KeyCompany, NameSubCompany )
VALUES    ( 1, 1, '1_SubCompany' ),
          ( 2, 1, '2_SubCompany' ),
          ( 3, 1, '3_SubCompany' ),
          ( 4, 1, '4_SubCompany' ),
          ( 5, 1, '5_SubCompany' ),
          ( 6, 1, '6_SubCompany' ),
          ( 7, 1, '7_SubCompany' )

CREATE TABLE EMPLOYEES
  (
    EMPLOYID NUMERIC(12, 0) ,
    KeySubCompany NUMERIC(12, 0) ,
    NAME VARCHAR(255)
  )


INSERT    INTO dbo.EMPLOYEES
          ( EMPLOYID, KeySubCompany, NAME )
VALUES    ( 1, 1, 'Winny' ),
          ( 1, 1, 'Justin' ),
          ( 1, 3, 'Mary' ),
          ( 1, 4, 'Leon' ),
          ( 1, 4, 'Marcy' ),
          ( 1, 7, 'Peter' )

我想要的结果是:

在表格Company我希望能够在我的报告中配置组织结构的深度(目前查看深度3)

我目前的解决方案:

WITH  CompanyRollup
    AS ( SELECT   C.KeyCompany ,
                  CASE WHEN ( GROUPING(O.O1) = 1 ) THEN ''
                       ELSE O.O1
                  END AS O1 ,
                  NULL AS O2 ,
                  NULL AS O3 ,
                  NULL AS O4 ,
                  NULL AS O5 ,
                  NULL AS O6 ,
                  NULL AS O7 ,
                  NULL AS O8 ,
                  NULL AS O9 ,
                  NULL AS O10 ,
                  NULL AS O11 ,
                  NULL AS O12 ,
                  1 AS viewDepth
         FROM     dbo.COMPANY C
                  INNER JOIN dbo.SUBCOMPANY SC ON SC.KeyCompany = C.KeyCompany
                                                  AND ( C.viewdepth + 1 ) = 1
                  INNER JOIN dbo.Organistation O ON O.KeySubCompany = SC.KeySubCompany
         GROUP BY C.KeyCompany ,
                  O.O1
                  WITH ROLLUP
         UNION
         SELECT   C.KeyCompany ,
                  CASE WHEN ( GROUPING(O.O1) = 1 ) THEN ''
                       ELSE O.O1
                  END AS O1 ,
                  CASE WHEN ( GROUPING(O.O2) = 1 ) THEN ''
                       ELSE O.O2
                  END AS O2 ,
                  NULL AS O3 ,
                  NULL AS O4 ,
                  NULL AS O5 ,
                  NULL AS O6 ,
                  NULL AS O7 ,
                  NULL AS O8 ,
                  NULL AS O9 ,
                  NULL AS O10 ,
                  NULL AS O11 ,
                  NULL AS O12 ,
                  2 AS viewDepth
         FROM     dbo.COMPANY C
                  INNER JOIN dbo.SUBCOMPANY SC ON SC.KeyCompany = C.KeyCompany
                                                  AND ( C.viewdepth + 1 ) = 2
                  INNER JOIN dbo.Organistation O ON O.KeySubCompany = SC.KeySubCompany
         GROUP BY C.KeyCompany ,
                  O.O1 ,
                  O.O2
                  WITH ROLLUP
         UNION
         SELECT   C.KeyCompany ,
                  CASE WHEN ( GROUPING(O.O1) = 1 ) THEN ''
                       ELSE O.O1
                  END AS O1 ,
                  CASE WHEN ( GROUPING(O.O2) = 1 ) THEN ''
                       ELSE O.O2
                  END AS O2 ,
                  CASE WHEN ( GROUPING(O.O3) = 1 ) THEN ''
                       ELSE O.O3
                  END AS O3 ,
                  NULL AS O4 ,
                  NULL AS O5 ,
                  NULL AS O6 ,
                  NULL AS O7 ,
                  NULL AS O8 ,
                  NULL AS O9 ,
                  NULL AS O10 ,
                  NULL AS O11 ,
                  NULL AS O12 ,
                  3 AS viewDepth
         FROM     dbo.COMPANY C
                  INNER JOIN dbo.SUBCOMPANY SC ON SC.KeyCompany = C.KeyCompany
                                                  AND ( C.viewdepth + 1 ) = 3
                  INNER JOIN dbo.Organistation O ON O.KeySubCompany = SC.KeySubCompany
         GROUP BY C.KeyCompany ,
                  O.O1 ,
                  O.O2 ,
                  O.O3
                  WITH ROLLUP
       )

SELECT  CR.KeyCompany ,
        SUM(SE.EMPLOYID) CountEmployees ,
        CR.O1 ,
        NULL AS O2,
        NULL AS O3,
        NULL AS O4,
        NULL AS O5,
        NULL AS O6,
        NULL AS O7,
        NULL AS O8,
        NULL AS O9,
        NULL AS O10,
        NULL AS O11,
        NULL AS O12
FROM    CompanyRollup CR
        INNER JOIN ( SELECT DISTINCT
                            KeyCompany ,
                            EMPLOYID
                     FROM   dbo.EMPLOYEES E
                            INNER JOIN dbo.SUBCOMPANY SSC ON SSC.KeySubCompany = E.KeySubCompany
                   ) SE ON SE.KeyCompany = CR.KeyCompany
        INNER JOIN ( SELECT SSSC.KeyCompany ,
                            SO.*
                     FROM   dbo.SUBCOMPANY SSSC
                            INNER JOIN dbo.Organistation SO ON SSSC.KeySubCompany = SO.KeySubCompany
                   ) SOO ON SOO.KeyCompany = CR.KeyCOmpany
                            AND ( CR.O1 = ''
                                  OR ISNULL(CR.O1, '') = ISNULL(SOO.O1, '')
                                )
WHERE   CR.Viewdepth = 1
GROUP BY CR.KeyCompany ,
        CR.O1 

  UNION
  SELECT  CR.KeyCompany ,
        SUM(SE.EMPLOYID) CountEmployees ,
        CR.O1 ,
        CR.O2 ,
        NULL  AS O3,
        NULL AS O4,
        NULL AS O5,
        NULL AS O6,
        NULL AS O7,
        NULL AS O8,
        NULL AS O9,
        NULL AS O10,
        NULL AS O11,
        NULL AS O12
FROM    CompanyRollup CR
        INNER JOIN ( SELECT DISTINCT
                            KeyCompany ,
                            EMPLOYID
                     FROM   dbo.EMPLOYEES E
                            INNER JOIN dbo.SUBCOMPANY SSC ON SSC.KeySubCompany = E.KeySubCompany
                   ) SE ON SE.KeyCompany = CR.KeyCompany
        INNER JOIN ( SELECT SSSC.KeyCompany ,
                            SO.*
                     FROM   dbo.SUBCOMPANY SSSC
                            INNER JOIN dbo.Organistation SO ON SSSC.KeySubCompany = SO.KeySubCompany
                   ) SOO ON SOO.KeyCompany = CR.KeyCOmpany
                            AND ( CR.O1 = ''
                                  OR ISNULL(CR.O1, '') = ISNULL(SOO.O1, '')
                                )AND ( CR.O2 = ''
                                  OR ISNULL(CR.O2, '') = ISNULL(SOO.O2, '')
                                )
WHERE   CR.Viewdepth = 2
GROUP BY CR.KeyCompany ,
        CR.O1,
        CR.O2 
    UNION
  SELECT  CR.KeyCompany ,
        SUM(SE.EMPLOYID) CountEmployees ,
        CR.O1 AS O1,
        CR.O2 AS O2,
        CR.O3 AS O3,
        NULL AS O4,
        NULL AS O5,
        NULL AS O6,
        NULL AS O7,
        NULL AS O8,
        NULL AS O9,
        NULL AS O10,
        NULL AS O11,
        NULL AS O12
FROM    CompanyRollup CR
        INNER JOIN ( SELECT DISTINCT
                            KeyCompany ,
                            EMPLOYID
                     FROM   dbo.EMPLOYEES E
                            INNER JOIN dbo.SUBCOMPANY SSC ON SSC.KeySubCompany = E.KeySubCompany
                   ) SE ON SE.KeyCompany = CR.KeyCompany
        INNER JOIN ( SELECT SSSC.KeyCompany ,
                            SO.*
                     FROM   dbo.SUBCOMPANY SSSC
                            INNER JOIN dbo.Organistation SO ON SSSC.KeySubCompany = SO.KeySubCompany
                   ) SOO ON SOO.KeyCompany = CR.KeyCOmpany
                            AND ( CR.O1 = ''
                                  OR ISNULL(CR.O1, '') = ISNULL(SOO.O1, '')
                                )AND ( CR.O2 = ''
                                  OR ISNULL(CR.O2, '') = ISNULL(SOO.O2, '')
                                ) AND ( CR.O3 = ''
                                  OR ISNULL(CR.O3, '') = ISNULL(SOO.O3, '')
                                )
WHERE   CR.Viewdepth = 3
GROUP BY CR.KeyCompany ,
        CR.O1,
        CR.O2,
        CR.O3.... UNION.... UNTIL O12

..... 以此类推,直到 O12

如您所见,它几乎只是复制/粘贴,只是组织结构有点不同。

有没有办法创建一个“更干净”的版本来创建这样的报告?

我创建了一个“简单”,它与我目前拥有的数据库/表具有相同的结构,因此无法更改表结构。

提前致谢。

在我忘记之前SQL Fiddle Demo

【问题讨论】:

标签: sql sql-server recursion common-table-expression rollup


【解决方案1】:

看看下面的东西。这是我知道的制作分层列表的最简单方法。如果您无法更改基础表结构,则在#temp 表中准备数据比创建 10 层嵌套 CTE 更容易。

SQLFiddle

CREATE TABLE Grp_lvl_1 (
  Id INT IDENTITY(1,1) NOT NULL,
  Name NVARCHAR(50))

CREATE TABLE Grp_lvl_2 (
  Id INT IDENTITY(1,1) NOT NULL,
  lvl_1_Id INT,
  Name NVARCHAR(50))

INSERT Grp_lvl_1 (Name) VALUES
('Continent_1'),
('Continent_2'),
('Continent_3')

INSERT Grp_lvl_2 (lvl_1_Id, Name) VALUES 
(1,'Country_1'),
(1,'Country_2'),
(1,'Country_3'),
(2,'Country_4'),
(2,'Country_5'),
(2,'Country_6'),
(3,'Country_7'),
(3,'Country_8'),
(3,'Country_9')

SELECT Grp_lvl_1.Name col1, Grp_lvl_2.Name col2
FROM Grp_lvl_1 INNER JOIN 
Grp_lvl_2 ON Grp_lvl_1.Id = Grp_lvl_2.lvl_1_Id

【讨论】:

    【解决方案2】:

    不,不需要递归CTEROLLUP 可以得到你的报告

    如果您使用 SQLServer 2008 或更高版本,HAVING 中的条件列表可以使用GROUPING_ID 替换为单个条件,它返回ROLLUPCUBE 和@987654329 中的分组级别@,作为位图的int值所以需要转换,位图与列的顺序相同,所以你想看到的细节越少,GROUPING_ID的值越低使用绑定。

    SELECT c.KeyCompany
         , COUNT(e.EMPLOYID) CountEmployees
         , o.o1, o.o2, o.o3, o.o4, o.o5, o.o6
         , o.o7, o.o8, o.o9, o.o10, o.o11, o.o12
    FROM   Organistation o
           INNER JOIN SUBCOMPANY s ON o.KeySubCompany = s.KeySubCompany
           INNER JOIN COMPANY c ON s.KeyCompany = c.KeyCompany
           INNER JOIN EMPLOYEES e ON o.KeySubCompany = e.KeySubCompany
    GROUP BY c.KeyCompany, RollUp(o.o1, o.o2, o.o3, o.o4, o.o5, o.o6
                                , o.o7, o.o8, o.o9, o.o10, o.o11, o.o12)
    HAVING GROUPING(o.o1) = 0
       AND GROUPING_ID(o.o1, o.o2, o.o3, o.o4, o.o5, o.o6
                     , o.o7, o.o8, o.o9, o.o10, o.o11, o.o12)
         > power(2, 11 - (MAX(c.viewdepth) + 1))
    ORDER BY COUNT(e.EMPLOYID)
    

    SQLFiddle演示

    如果您使用的是 SQLServer 2005 或更早的版本,则查询会更加冗长

    SELECT c.KeyCompany
         , COUNT(e.EMPLOYID) CountEmployees
         , o.o1, o.o2, o.o3, o.o4, o.o5, o.o6
         , o.o7, o.o8, o.o9, o.o10, o.o11, o.o12
    FROM   Organistation o
           INNER JOIN SUBCOMPANY s ON o.KeySubCompany = s.KeySubCompany
           INNER JOIN COMPANY c ON s.KeyCompany = c.KeyCompany
           INNER JOIN EMPLOYEES e ON o.KeySubCompany = e.KeySubCompany
    GROUP BY c.KeyCompany, RollUp(o.o1, o.o2, o.o3, o.o4, o.o5, o.o6
                                , o.o7, o.o8, o.o9, o.o10, o.o11, o.o12)
    HAVING GROUPING(o.o1) = 0
       AND (GROUPING(o.o1) = 1 OR (GROUPING(o.o1) = 0 AND MAX(c.viewdepth) + 1 >= 1))
       AND (GROUPING(o.o2) = 1 OR (GROUPING(o.o2) = 0 AND MAX(c.viewdepth) + 1 >= 2))
       AND (GROUPING(o.o3) = 1 OR (GROUPING(o.o3) = 0 AND MAX(c.viewdepth) + 1 >= 3))
       AND (GROUPING(o.o4) = 1 OR (GROUPING(o.o4) = 0 AND MAX(c.viewdepth) + 1 >= 4))
       AND (GROUPING(o.o5) = 1 OR (GROUPING(o.o5) = 0 AND MAX(c.viewdepth) + 1 >= 5))
       AND (GROUPING(o.o6) = 1 OR (GROUPING(o.o6) = 0 AND MAX(c.viewdepth) + 1 >= 6))
       AND (GROUPING(o.o7) = 1 OR (GROUPING(o.o7) = 0 AND MAX(c.viewdepth) + 1 >= 7))
       AND (GROUPING(o.o8) = 1 OR (GROUPING(o.o8) = 0 AND MAX(c.viewdepth) + 1 >= 8))
       AND (GROUPING(o.o9) = 1 OR (GROUPING(o.o9) = 0 AND MAX(c.viewdepth) + 1 >= 9))
       AND (GROUPING(o.o10) = 1 OR (Grouping(o.o10) = 0 
                                AND MAX(c.viewdepth) + 1 >= 10))
       AND (GROUPING(o.o11) = 1 OR (GROUPING(o.o11) = 0
                                AND MAX(c.viewdepth) + 1 >= 11))
       AND (GROUPING(o.o12) = 1 OR (GROUPING(o.o12) = 0
                                AND MAX(c.viewdepth) + 1 >= 12))
    ORDER BY COUNT(e.EMPLOYID)
    

    诀窍在于HAVING,行

    (GROUPING(o.o4) = 1 OR (GROUPING(o.o4) = 0 AND MAX(c.viewdepth) + 1 >= 4))
    

    删除由 ROLLUP 返回的所有未分组 (Grouping(o.o4) = 1) 或深度低于所需最大值 (GROUPING(o.o4) = 0 AND MAX(c.viewdepth) + 1 >= 4)) 的行。

    SQLFiddle演示

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 2012-04-23
      • 2014-05-19
      • 2012-12-25
      • 1970-01-01
      • 1970-01-01
      • 2020-06-08
      • 1970-01-01
      相关资源
      最近更新 更多