【问题标题】:How to find and remove child_id if parent_id exist already如果 parent_id 已经存在,如何查找和删除 child_id
【发布时间】:2021-09-29 09:52:29
【问题描述】:

我在父子结构和扁平结构中都有 2 个层次结构数据表

父子表:

PARENT_ID   CHILD_ID 
1234        1111 
1234        2222 
1234        3333 
3333        33XX 
3333        33YY

扁平结构:

LEVEL_1 LEVEL_2 LEVEL_3
1234    1111    
1234    2222    
1234    3333    33XX
1234    3333    33YY

我有另一个用户表,其中包含哪个用户可以访问哪个 ID

USER_ID   USER_ACCESS
USER_A    1234,1111 
USER_B    33YY,3333,1234

我已将上表进一步转换为以下格式

USER_ID   USER_ACCESS
USER_A    1234
USER_A    1111 
USER_B    33YY
USER_B    3333
USER_B    1234

如果他的 ID 已经存在 parent_id,我需要为每个用户查找并删除 child_id

上面的示例输出

USER_ID   USER_ACCESS
USER_A    1234
USER_B    1234

需要在任一 Oracle/SQL Server 中避免任何循环的解决方案。

【问题讨论】:

  • 我迷路了。你说。你有“一张桌子”。然后你有两列和三列的示例数据。那不是一张桌子。
  • 而 USER_ACCESS 是“csv 列”?喜悦
  • @CaiusJard 它是一个 varchar 列,ID 用逗号分隔
  • 太可惜了。
  • @CaiusJard 为什么会这样?

标签: sql sql-server oracle


【解决方案1】:

神谕

Parent Child 表的设计太糟糕了,你最好添加child_id:1234 的行,就像tab1 一样

with tab1 as (
SELECT * FROM struct_info union all
SELECT distinct null, t1.parent_id FROM struct_info t1 
 where t1.parent_id not in (select distinct v1.child_id from struct_info v1)
)
,tab2 as (
select t1.*,
       level lv
  from tab1 t1
 start with t1.parent_id is null
connect by prior t1.child_id = t1.parent_id
)
select distinct 
       t2.user_id,
       first_value(t1.child_id) over(partition by t2.user_id order by t1.lv)
  from tab2 t1,
       access_info t2
 where t1.child_id = t2.user_access
;

【讨论】:

    【解决方案2】:

    先说几句:

    拥有层次结构已经使扁平化结构的需求过时。 此外,扁平表永远无法容纳层次结构的所有级别。您添加的每个级别都需要您添加一个额外的列,这很可笑。

    以您需要用逗号分隔键的方式存储用户访问权限,没有(好的)方法来验证表之间的约束。

    话虽如此(并且使用不需要字符串拆分的表):

    
    DROP TABLE IF EXISTS #struct_info;
    CREATE TABLE #struct_info (
      PARENT_ID VARCHAR(50),
      CHILD_ID VARCHAR(50)
    );
    
    DROP TABLE IF EXISTS #access_info;
    CREATE TABLE #access_info (
      USER_ID VARCHAR(50),
      USER_ACCESS VARCHAR(50)
    );
    
    INSERT INTO #struct_info
    (
      PARENT_ID,
      CHILD_ID
    )
    VALUES
    ('1234','1111'),
    ('1234','2222'),
    ('1234','3333'),
    ('3333','33XX'),
    ('3333','33YY')
    
    INSERT INTO #access_info
    (
      USER_ID,
      USER_ACCESS
    )
    VALUES
    ('USER_A','1234'),
    ('USER_A','1111'),
    ('USER_B','33YY'),
    ('USER_B','3333'),
    ('USER_B','1234')
    
    
    SELECT * FROM #struct_info
    SELECT * FROM #access_info
    
    ;WITH cte AS (
      SELECT 
        PARENT_ID,
        CHILD_ID
      FROM #struct_info
      UNION ALL
      SELECT
        cte.PARENT_ID,
        si.CHILD_ID
      FROM cte
      INNER JOIN #struct_info si
        ON si.PARENT_ID = cte.CHILD_ID
    )
    DELETE ai
    FROM #access_info ai
    WHERE EXISTS (
         SELECT 1
         FROM cte 
         WHERE cte.CHILD_ID = ai.USER_ACCESS
           AND EXISTS (SELECT 1 
                       FROM #access_info ai2 
                       WHERE ai2.USER_ID = ai.USER_ID
                         AND ai2.USER_ACCESS =  cte.PARENT_ID)
      )
    
    SELECT * FROM #access_info
    
    

    cte 确定所有可能的层次结构变体 删除查找可以在该变体中找到父代的任何 child_id

    【讨论】:

      猜你喜欢
      • 2011-01-18
      • 2018-12-13
      • 2021-05-07
      • 1970-01-01
      • 2018-03-15
      • 2016-02-05
      • 1970-01-01
      • 2015-10-21
      • 2016-07-16
      相关资源
      最近更新 更多