【问题标题】:Identify root node with group by使用 group by 识别根节点
【发布时间】:2018-07-18 16:34:52
【问题描述】:

我需要在其层次结构下仅设置一组标志来识别主要通道(层次结构中最高的)。在以下情况下,US 不是有效的主要渠道,因为下面有两个标志。只有 US1、US2、UK 是有效的主要渠道。

如果可能的话,我希望有一个单一查询的解决方案;否则我将探索程序选项。

我尝试了分层查询、分组依据、计数(标志)的一些变体,但不知何故我无法消除“美国”并获得所需的结果。

如果有人可以帮助我为这个用例提供高级方法,我将不胜感激。

输入数据

---------------------------------
channel | flag  | parent channel
---------------------------------
US      |       |               

US1     |       | US        
A1      | yes   | US1       
A2      |       | A1        
A3      |       | A2

US2     |       | US        
B1      |       | US2       
B2      | yes   | B1        
B3      |       | B2        

UK      |       |   
C1      |       | UK        
C2      |       | C1        
C3      | yes   | C2        
---------------------------------

使用输入数据的带有标志计数的多个层次结构

---------------------
channel | flag count 
---------------------
US      | 2     

US1     | 1     
A1      | 1 
A2      | 0      
A3      | 0      

US2     | 1     
B1      | 1      
B2      | 1   
B3      | 0      

UK      | 1      
C1      | 1      
C2      | 1      
C3      | 1   
----------------

输出

---------------------------------
primary channel
---------------------------------
US1
US2
UK
---------------------------------

【问题讨论】:

  • 当 US1 和 US2 都在 US 之下时,为什么它们是“等级最高的”?消除美国并包括英国似乎还可以,但我不明白最终结果中如何包括 US1 和 US2?您将 US 列为根节点(没有父节点)两次,这也令人困惑。
  • 参考编辑,我已经添加了中间结果集。您会注意到,通过使用输入数据,我们可以创建多个具有下方标志计数的层次结构。主要通道将是只有一个标志计数的通道,并且应该在层次结构中最高。是的,删除了重复的美国条目。

标签: sql oracle group-by hierarchical-data hierarchical-query


【解决方案1】:

这有点棘手......当然,除非我错过了一个明显的捷径......

select max(channel) keep (dense_rank last order by lvl) as primary_channel
from (
  select channel, connect_by_root(channel) as root, level lvl,
    count(*) over (partition by channel) as flag_count
  from input_data
  connect by channel = prior parent_channel
  start with flag = 'yes'
)
where flag_count = 1
group by root;

PRIMARY_CHANNEL
---------------
US1
US2
UK

db<>fiddle demo.

内部查询是一个相当简单的分层查询,从三个flag = 'yes' 行向上遍历树,除了它还对每个channel 在生成的层次结构中出现的次数进行分析计数。

select channel, connect_by_root(channel) as root, level lvl,
  count(*) over (partition by channel) as flag_count
from input_data
connect by channel = prior parent_channel
start with flag = 'yes';

CHANNEL ROOT        LVL FLAG_COUNT
------- ---- ---------- ----------
A1      A1            1          1
B1      B2            2          1
B2      B2            1          1
C1      C3            3          1
C2      C3            2          1
C3      C3            1          1
UK      C3            4          1
US      A1            3          2
US      B2            4          2
US1     A1            2          1
US2     B2            3          1

11 rows selected. 

然后,外部查询会消除计数大于 1 的任何位置 - 即两个 US 行;并使用另一个分析函数为结果中剩余的每个根找到具有最高级别的行。


我假设US 实际上只在您的input_data 中出现过一次;但如果它存在两次,那么这仍然有效,中间计数仅为 4 而不是 2。您可以在 this db<>fiddle 中看到该版本。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2011-04-19
    • 1970-01-01
    相关资源
    最近更新 更多