【问题标题】:Need sql query to find the lowest level of values in a hierarchy需要 sql 查询来查找层次结构中最低级别的值
【发布时间】:2021-09-15 22:09:49
【问题描述】:

表组织(organizationId, parentId, name) 表设置(id, organizationId, settingName, settingValue)

这里是 |a,1| : a 是设置名称,1 是设置值

Organization A   |a,1|    |b,2|    |c,3|    |d,4|
Organization B            |b,5|
Organization C   |a,8|
Organization D                     |c,2|

A->B->C->D(层次结构) 现在得到组织 D 的查询应该给我 (a,8)(b,5)(c,2)(d,4)

我的查询:

with recursive cte as (
select
    *, 1 as level
from
    Organization
where
    organizationId = 3
union ALL 
select
    t.*, cte.level+1
from
    cte
join Organization t on
    t.OrganizationId = cte.parentId )
-- select
    --  ss.OrganizationId,ss.parentId, ss.settingName,ss.settingValue
-- from 
    select
        cte.OrganizationId,
        cte.ParentId,
        s.settingName ,
        s.settingValue,
        level
    from
        cte
    inner join Settings s on
        s.organizationId = cte.OrganizationId
        -- as ss group by ss.settingName
        

这给了我来自所有组织的设置,但我需要来自父母的最新孩子的值(如果有的话)(这应该一直持续到 ROOT 组织,自下而上的方法)

Settings Table Data

Organization table Data

【问题讨论】:

  • 是的,它给了我所有的设置,我需要从下到上的设置。所以基本上 settingName 将是唯一的,因为最新的设置将从孩子那里获取。
  • 请描述获取设置的规则。为什么预期输出包含组织 A 的(d, 4)?并以表格格式或作为插入语句提供源数据。
  • @astentx 将数据作为图像的一部分提供,它应该为组织 D 获取 (d,4) 因为它必须向上遍历根并仅获取具有最近更新的值(如果有)没有更新换旧的。
  • 您有一些预定义的设置,如果节点没有此设置,您希望从节点本身或其父节点获取每个设置的值。我说的对吗?

标签: mysql parent-child jooq hierarchical-data recursive-query


【解决方案1】:

跟踪感兴趣的 orgId 和设置级别。按级别查找第一个值

with recursive cte as (
   select  s.*, 1 as level, s.organizationId  as orgId
   from    Settings s 
   where   s.organizationId = 4
   union ALL 
   select   s.*, cte.level+1, cte.orgId
   from cte 
   join    Organization t on t.organizationId = cte.organizationId 
   join    settings s on s.organizationId = t.ParentId  
)
select distinct orgid, settingname, first_value(settingvalue) over(partition by orgId, settingname order by level)
from cte

编辑 组织不能有设置的情况

with recursive cte as (
   select  t.organizationId, s.settingname, s.settingvalue, 1 as level, t.organizationId orgId
   from    Organization t
   left join Settings s on t.organizationId = s.organizationId 
   where   t.organizationId = 5
   
   union ALL 
   
   select   t.ParentId, s.settingname, s.settingvalue, cte.level+1, cte.orgId
   from cte 
   join    Organization t on t.organizationId = cte.organizationId 
   left join    settings s on s.organizationId = t.ParentId  
)
select distinct orgid, settingname, first_value(settingvalue) over(partition by orgId, settingname order by level)
from  cte
where settingName is not null 
order by orgid, settingname;

db<>fiddle

【讨论】:

  • 在一定程度上是有用的。谢谢好先生。创建具有空设置的新组织应提供上述子级的设置,如果存在,则从父级获取。目前它返回空列表。
  • 组织 4 仅有一个设置。它有什么问题?
  • 查看没有设置案例的组织的编辑。
  • 谢谢先生。它有效,但还有一个问题。创建一些具有空设置的新组织应该提供上述子级的设置,如果存在,则从父级获取。目前它返回空列表。就像 (A->B->C->D->E) D 和 E 是空的。如果我查询 E,它应该给出来自 C 的值。
  • 组织 4 与一个设置工作。抱歉,我的错。
【解决方案2】:

创建架构

create table t42 (id number, parent_id number, flag varchar2(1), str
varchar2(20));

insert into t42 values (1, null, 'A', 'Parent');

insert into t42 values (2, 1, 'B', 'Child 1'); insert into t42
values (3, 1, 'C', 'Child 2'); insert into t42 values (4, 1, 'C',
'Child 3');

insert into t42 values (5, 2, 'D', 'Grandchild 1 1'); insert into
t42 values (6, 3, 'B', 'Grandchild 2 1'); insert into t42 values (7,
3, 'D', 'Grandchild 2 2');

现在执行下面的查询

select t.id, t.parent_id, t.flag, t.str
from (
  select t.*, dense_rank() over (partition by flag order by lvl) as rn
  from (
    select t.*, level as lvl
    from t42 t
    start with parent_id is null
    connect by prior id = parent_id
  ) t
) t
where rn = 1
and flag = 'A';

select t.id, t.parent_id, t.flag, t.str
from (
  select t.*, dense_rank() over (partition by flag order by lvl) as rn
  from (
    select t.*, level as lvl
    from t42 t
    start with parent_id is null
    connect by prior id = parent_id
  ) t
) t
where rn = 1
and flag = 'B';

select t.id, t.parent_id, t.flag, t.str
from (
  select t.*, dense_rank() over (partition by flag order by lvl) as rn
  from (
    select t.*, level as lvl
    from t42 t
    start with parent_id is null
    connect by prior id = parent_id
  ) t
) t
where rn = 1
and flag = 'C';

select t.id, t.parent_id, t.flag, t.str
from (
  select t.*, dense_rank() over (partition by flag order by lvl) as rn
  from (
    select t.*, level as lvl
    from t42 t
    start with parent_id is null
    connect by prior id = parent_id
  ) t
) t
where rn = 1
and flag = 'D';

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2013-10-28
    • 1970-01-01
    • 1970-01-01
    • 2015-06-25
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多