Как переписать иерархический запрос Oracle sql на поляры?

В Oracle у меня есть следующий иерархический SQL:

with prod as (select 10 id,'1008' code from dual union all
              select 11 id,'1582' code from dual union all
              select 12 id,'1583' code from dual union all
              select 13 id,'2023' code from dual union all
              select 14 id,'2025' code from dual union all
              select 15 id,'2030' code from dual union all
              select 16 id,'2222' code from dual
              ),
     prre as (select 10 detail_product_id,90 master_product_id from dual union all
              select 12 detail_product_id,11 master_product_id from dual union all
              select 91 detail_product_id,92 master_product_id from dual union all
              select 14 detail_product_id,12 master_product_id from dual union all
              select 90 detail_product_id,93 master_product_id from dual union all
              select 11 detail_product_id,91 master_product_id from dual union all
              select 15 detail_product_id,12 master_product_id from dual union all
              select 13 detail_product_id,12 master_product_id from dual union all
              select 94 detail_product_id,95 master_product_id from dual
              )
select
   prod.code,
   connect_by_root prod.code group_type
from prre,prod
where prre.detail_product_id = prod.id
connect by nocycle prior prre.detail_product_id = prre.master_product_id
start with prod.code in ('1008', '1582')

В результате чего:

CODE    GROUP_TYPE
1582    1582
1583    1582
2030    1582
2025    1582
2023    1582
1008    1008

Как я могу переписать его на поляры? Начальный dfs будет выглядеть так:

import polars as pl
prod = pl.DataFrame({'id': [10,11,12,13,14,15,16],
                     'code': ['1008','1582','1583','2023','2025','2030','2222']
                     })
prre = pl.DataFrame({'detail_product_id': [10,12,91,14,90,11,15,13,94],
                     'master_product_id': [90,11,92,12,93,91,12,12,95]
                     })

Но как быть дальше?
Задача на простом английском языке:

  • начните с prod df, где код «1008» или «1582».
  • возьмите соответствующий идентификатор
  • используя этот цикл идентификатора через prre df: где бы вы ни нашли этот идентификатор в поле Detail_product_id, соответствующий код prod df будет в списке результатов вместе со значением корневого кода (с именем group_type)
  • просмотрите master_product_id-s до этих Detail_product_id-ов рекурсивно, повторяя предыдущий шаг

Найденная структура выглядит следующим образом:

11 -> 1582
|-12 -> 1583
  |-13 -> 2023
  |-14 -> 2025
  |-15 -> 2030
Почему в Python есть оператор "pass"?
Почему в Python есть оператор "pass"?
Оператор pass в Python - это простая концепция, которую могут быстро освоить даже новички без опыта программирования.
Некоторые методы, о которых вы не знали, что они существуют в Python
Некоторые методы, о которых вы не знали, что они существуют в Python
Python - самый известный и самый простой в изучении язык в наши дни. Имея широкий спектр применения в области машинного обучения, Data Science,...
Основы Python Часть I
Основы Python Часть I
Вы когда-нибудь задумывались, почему в программах на Python вы видите приведенный ниже код?
LeetCode - 1579. Удаление максимального числа ребер для сохранения полной проходимости графа
LeetCode - 1579. Удаление максимального числа ребер для сохранения полной проходимости графа
Алиса и Боб имеют неориентированный граф из n узлов и трех типов ребер:
Оптимизация кода с помощью тернарного оператора Python
Оптимизация кода с помощью тернарного оператора Python
И последнее, что мы хотели бы показать вам, прежде чем двигаться дальше, это
Советы по эффективной веб-разработке с помощью Python
Советы по эффективной веб-разработке с помощью Python
Как веб-разработчик, Python может стать мощным инструментом для создания эффективных и масштабируемых веб-приложений.
1
0
81
1
Перейти к ответу Данный вопрос помечен как решенный

Ответы 1

Ответ принят как подходящий

По сути, вам нужен рекурсивный запрос. Если вы хотите чистые поляры, то, боюсь, вам придется присоединяться итеративно.

Идея относительно проста. Сначала вы создаете начальный фрейм данных с помощью filter() . Затем во время каждой итерации вы используете join() для создания кадра данных, содержащего следующий уровень иерархии. Во время итерации вы сохраняете эти кадры данных в список. Итерации прекращаются, когда вы доходите до конца иерархии. В конце вы используете .concat(), чтобы объединить все фреймы данных вместе.

df = (
    prod
    .filter(pl.col.code.is_in(['1008', '1582']))
    .with_columns(group_type = pl.col.code)
)
dfs = [df]

while True:
    df = df.join(prre, left_on = "id", right_on = "master_product_id")
    if df.height == 0:
        break
    df = (
        prod
        .join(df, left_on = "id", right_on = "detail_product_id")
        .select("id", "code", "group_type")
    )

    dfs.append(df)

pl.concat(dfs).drop("id")

┌──────┬────────────┐
│ code ┆ group_type │
│ ---  ┆ ---        │
│ str  ┆ str        │
╞══════╪════════════╡
│ 1008 ┆ 1008       │
│ 1582 ┆ 1582       │
│ 1583 ┆ 1582       │
│ 2023 ┆ 1582       │
│ 2025 ┆ 1582       │
│ 2030 ┆ 1582       │
└──────┴────────────┘

Но вы также можете использовать интеграцию DuckDB с полярами и рекурсивным cte

import duckdb

duckdb.sql("""
    with recursive cte as (
        select
            d.code,
            d.code as group_type,
            d.id,
            1 as depth
        from prod as d
        where
            d.code in ('1008', '1582')

        union all

        select
            d.code,
            c.group_type,
            d.id,
            c.depth + 1
        from cte as c
            inner join prre as p on
                p.master_product_id = c.id
            inner join prod as d on
                d.id = p.detail_product_id
    )
    select
        code,
        group_type,
        depth
    from cte as c
    order by
        depth asc
""")

┌─────────┬────────────┬───────┐
│  code   │ group_type │ depth │
│ varchar │  varchar   │ int32 │
├─────────┼────────────┼───────┤
│ 1008    │ 1008       │     1 │
│ 1582    │ 1582       │     1 │
│ 1583    │ 1582       │     2 │
│ 2023    │ 1582       │     3 │
│ 2025    │ 1582       │     3 │
│ 2030    │ 1582       │     3 │
└─────────┴────────────┴───────┘

Другие вопросы по теме