Ієрархії в ABAP SQL
Ієрархічні дані — структури parent-child: організації, матеріали (BOM), дерева категорій. На HANA ABAP SQL має нативну підтримку: ієрархію описуєш один раз (CDS, HIERARCHY-генератор або CTE), далі ходиш по ній через навігатори HIERARCHY_DESCENDANTS, HIERARCHY_ANCESTORS, HIERARCHY_SIBLINGS та аґреґат-версії.
Раніше довелось би писати рекурсію або AMDP зі SQLScript. Зараз — декларативно, через стандартний ABAP SQL.
Три способи створити ієрархію
Section titled “Три способи створити ієрархію”1. CDS hierarchy (рекомендовано для перевикористання)
Section titled “1. CDS hierarchy (рекомендовано для перевикористання)”Визначається окремим обʼєктом DEFINE HIERARCHY, спираючись на CDS view з self-association. Найстійкіший варіант: логіка ієрархії винесена з програми, можна захистити через DCL.
// CDS view з self-асоціацієюdefine view entity zdemo_nodes as select from zdemo_abap_hnodes association [0..1] to zdemo_nodes as _parent on $projection.parent_id = _parent.id { key id, parent_id, name, _parent }// Hierarchydefine hierarchy zdemo_node_hier with parameters p_root : abap.numc(4) as parent child hierarchy( source zdemo_nodes child to parent association _parent start where id = :p_root siblings order by name ) { id, parent_id, name }2. HIERARCHY() — SQL-генератор
Section titled “2. HIERARCHY() — SQL-генератор”Той самий синтаксис, але inline у ABAP SQL. Зручно для одноразового використання:
SELECT * FROM HIERARCHY( SOURCE zdemo_nodes CHILD TO PARENT ASSOCIATION _parent START WHERE id = @root SIBLINGS ORDER BY name ) INTO TABLE @DATA(tree).3. CTE як джерело ієрархії
Section titled “3. CTE як джерело ієрархії”CTE оголошується ієрархією через додаток WITH HIERARCHY <name> (посилається на існуючий CDS hierarchy). Після цього з CTE можна читати неявні hierarchy-колонки:
WITH +tree AS ( SELECT FROM zdemo_node_hier( p_root = @root ) FIELDS * ) WITH HIERARCHY zdemo_node_hier SELECT FROM +tree FIELDS id, name, hierarchy_level, hierarchy_rank INTO TABLE @DATA(out).Також можна використати HIERARCHY( ... ) як джерело всередині CTE — як у прикладі вище з inline-генератором.
Неявні hierarchy-колонки
Section titled “Неявні hierarchy-колонки”Доступні автоматично при виборці з ієрархії:
| Колонка | Значення |
|---|---|
hierarchy_rank | Порядковий номер у обході (preorder) |
hierarchy_tree_size | Кількість нащадків + 1 (розмір піддерева) |
hierarchy_parent_rank | Rank батька |
hierarchy_level | Глибина (root = 1) |
hierarchy_is_cycle | Прапорець: вузол у циклі |
hierarchy_is_orphan | Прапорець: сирота (батько не знайдений) |
Навігатори
Section titled “Навігатори”HIERARCHY_DESCENDANTS — нащадки
Section titled “HIERARCHY_DESCENDANTS — нащадки”Повертає усіх нащадків заданих стартових вузлів. Додає колонку HIERARCHY_DISTANCE (≥ 0 — скільки рівнів донизу).
SELECT * FROM HIERARCHY_DESCENDANTS( SOURCE zdemo_node_hier( p_root = '0001' ) START WHERE id = @start_node DISTANCE FROM 1 TO 3 ) " опціонально обмежити діапазон глибини INTO TABLE @DATA(desc).Параметр DISTANCE обмежує, на скільки рівнів донизу йти від стартового вузла. Без нього — без обмежень.
HIERARCHY_ANCESTORS — предки
Section titled “HIERARCHY_ANCESTORS — предки”Те саме, але вгору: повертає предків від стартового вузла до кореня. Колонка HIERARCHY_DISTANCE показує, скільки рівнів догори від стартового вузла (≥ 0).
SELECT * FROM HIERARCHY_ANCESTORS( SOURCE zdemo_node_hier( p_root = '0001' ) START WHERE id = @leaf ) INTO TABLE @DATA(anc).HIERARCHY_SIBLINGS — “брати”
Section titled “HIERARCHY_SIBLINGS — “брати””Вузли з тим самим батьком. Додає HIERARCHY_SIBLING_DISTANCE.
SELECT * FROM HIERARCHY_SIBLINGS( SOURCE zdemo_node_hier( p_root = '0001' ) START WHERE id = @node ) INTO TABLE @DATA(sib).Аґреґат-навігатори
Section titled “Аґреґат-навігатори”HIERARCHY_DESCENDANTS_AGGREGATE і HIERARCHY_ANCESTORS_AGGREGATE — аґреґують значення по піддереву/по шляху до кореня.
" Сума amount по піддереву кожного вузлаSELECT * FROM HIERARCHY_DESCENDANTS_AGGREGATE( SOURCE zdemo_node_hier( p_root = '0001' ) AS h JOIN @values AS v ON v~id = h~id MEASURES SUM( v~amount ) AS total WHERE hierarchy_rank > 1 WITH SUBTOTAL WITH BALANCE ) INTO TABLE @DATA(totals).MEASURES— які аґреґати обчислити (SUM,MIN,MAX,AVG,COUNT).WHERE(післяMEASURES) — відбирає вузли, для яких обчислюєтьсяSUBTOTAL.WITH SUBTOTAL— додає рядки-підсумки для вузлів, що збігаються зWHERE.WITH BALANCE— додає рядки-різниці для решти вузлів.
Колонка HIERARCHY_AGGREGATE_TYPE: 1 — subtotal, 2 — balance.
Типові задачі → який навігатор
Section titled “Типові задачі → який навігатор”| Задача | Інструмент |
|---|---|
| Показати дерево від кореня | HIERARCHY() або CDS hierarchy |
| ”Усі підрозділи під цим департаментом” | HIERARCHY_DESCENDANTS |
| ”Шлях від листа до кореня” | HIERARCHY_ANCESTORS |
| ”Сусідні категорії” | HIERARCHY_SIBLINGS |
| ”Сума витрат по піддереву” | HIERARCHY_DESCENDANTS_AGGREGATE |
| ”Накопичена сума вгору по дереву” | HIERARCHY_ANCESTORS_AGGREGATE |
Адаптовано з 10_ABAP_SQL_Hierarchies.md (Apache 2.0). Повний перелік нюансів — в оригіналі.