【问题标题】:Get root elements for list of children in hierarchical table获取分层表中子级列表的根元素
【发布时间】:2020-06-14 09:43:38
【问题描述】:

我有以下 2 个表,第一个表中有分层数据:

公司:

COMPANY_ID    PARENT_COMPANY_ID
----------    -----------------
1             NULL
2             1
3             2
4             3
5             NULL
6             5

用户:

USER_ID       COMPANY_ID
-------       ----------
1             1
2             4
3             5
4             6

我想做一个查询,在他们的根公司 ID 旁边输出用户 ID。我已尝试使用以下公用表表达式 (CTE) 查询,但它无法输出直接位于根公司下的用户:

查询:

WITH ROOT (COMPANY_ID, ROOT_ID) AS (
  SELECT
    CHILD.COMPANY_ID,
    PARENT.COMPANY_ID
  FROM COMPANIES CHILD
  INNER JOIN COMPANIES PARENT
  ON CHILD.PARENT_COMPANY_ID = PARENT.COMPANY_ID
  WHERE
    PARENT.PARENT_COMPANY_ID IS NULL
  UNION ALL
  SELECT
    C.COMPANY_ID,
    ROOT.ROOT_ID
  FROM ROOT
  INNER JOIN COMPANIES C
  ON ROOT.COMPANY_ID = C.PARENT_COMPANY_ID
  )
SELECT
  U.USER_ID,
  R.ROOT_ID
FROM USERS U
INNER JOIN ROOT R
ON U.COMPANY_ID = R.COMPANY_ID;

实际输出:

USER_ID    ROOT_COMPANY_ID
-------    ---------------
4             5
2             1

预期输出:

USER_ID    ROOT_COMPANY_ID
-------    ---------------
1             1
2             1
3             5
4             5

所以我的查询缺少用户 ID 为 1 和 2 的用户,他们各自的根公司为 1 和 5。

我用我的例子创建了这个 sqlfiddle: http://sqlfiddle.com/#!4/36d33a/1

我在这里错过了什么?

我使用的是 Oracle 11,但使用 H2 进行单元测试。所以我的查询需要是 CTE 查询而不是 Oracle 查询连接,因为 H2 只理解前者。

【问题讨论】:

    标签: sql oracle oracle11g h2 common-table-expression


    【解决方案1】:

    对于根公司,您需要选择 COMPANY_ID 作为 COMPANY_IDROOT_ID

    WITH ROOT(COMPANY_ID, ROOT_ID) AS (
       SELECT COMPANY_ID, COMPANY_ID FROM COMPANIES WHERE PARENT_COMPANY_ID IS NULL
    UNION ALL
       SELECT C.COMPANY_ID, ROOT.ROOT_ID FROM COMPANIES C JOIN ROOT
           ON C.PARENT_COMPANY_ID = ROOT.COMPANY_ID
    ) SELECT USER_ID, ROOT_ID FROM USERS JOIN ROOT
        ON USERS.COMPANY_ID = ROOT.COMPANY_ID;
    

    【讨论】:

      【解决方案2】:

      您可以使用Oracle的经典分层查询包括CONNECT_BY_ROOTROW_NUMBER()分析函数在companies表的第一个查询(子查询)中过滤掉根公司,然后与users表连接:

      WITH company AS
      (
       SELECT c.company_id, 
              CONNECT_BY_ROOT NVL(c.parent_company_id,c.company_id) AS root_company_id,
              ROW_NUMBER() OVER (PARTITION BY c.company_id ORDER BY level DESC) AS rn
         FROM companies c
      CONNECT BY PRIOR c.company_id = c.parent_company_id
      )
      SELECT u.user_id, c.root_company_id
        FROM company c
        JOIN users u
          ON u.company_id = c.company_id
       WHERE rn = 1 
      

      Demo

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 2015-10-03
        • 2016-03-19
        • 2019-09-30
        • 1970-01-01
        • 2020-04-23
        • 2021-08-20
        • 2021-07-14
        • 1970-01-01
        相关资源
        最近更新 更多