Поддержка DuckDB для функции Postgres С ОБЫЧНОСТЬЮ

В настоящее время я использую DuckDB для выполнения следующего запроса Postgres, содержащего функцию FORDINALITY в фрейме данных Polars:

with suffixes as (
select ordrnbr,(nr-1)/2 N
  ,max(case when nr%2=1 then elem end) Nkey
  ,cast(max(case when nr%2=0 then elem end) as int) Nval
from test t
left join lateral unnest(string_to_array(t.description, '@'))
                    WITH ORDINALITY AS a(elem, nr) ON true
group by ordrnbr,(nr-1)/2
)

select concat(t.ordrnbr,'-',row_number()over(partition by t.ordrnbr order by s.N))ordrnbr
  , vehiclename,    description,    id, totprice
  ,coalesce(s.Nval,totprice) ind_price
from test t
left join suffixes s on s.ordrnbr=t.ordrnbr
where s.Nval>=10000 or (s.Nval is null and totPrice>=10000)

Когда я попытался выполнить этот запрос, Duck DB выдает ошибку

исключение: duckdb.duckdb.NotImplementedException: не реализовано Ошибка: С ОБЫЧНЫМ значением не реализовано.

Есть ли другой способ добиться этого с помощью DuckDB?

Любая помощь будет оценена, пожалуйста.

Почему в 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
104
1
Перейти к ответу Данный вопрос помечен как решенный

Ответы 1

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

Решение DuckDB:

Вы можете использовать generate_subscripts() для генерации индексов по размеру массива.

Чтобы немного упростить пример, допустим, вы хотите разделить hello@world

select
    unnest(a.data) as v, generate_subscripts(a.data, 1) as i
from values (
    string_to_array('hello@world', '@')
) as a(data)

┌─────────┬───────┐
│    v    │   i   │
│ varchar │ int64 │
├─────────┼───────┤
│ hello   │     1 │
│ world   │     2 │
└─────────┴───────┘

Ваш запрос может выглядеть примерно так:

with nr as (
    select
        t.ordrnbr,
        unnest(v.description) as elem,
        generate_subscripts(v.description, 1) as nr
    from test t,
        values (string_to_array(t.description, '@')) as v(description)
), suffixes as (
    select
        t.ordrnbr,
        (t.nr - 1) / 2 as N,
        max(case when t.nr % 2 = 1 then t.elem end) as Nkey,
        cast(max(case when t.nr % 2 = 0 then t.elem end) as int) as Nval
    from nr as t
    group by
        ordrnbr,
        (t.nr - 1) / 2
)
select
    concat(t.ordrnbr, '-', row_number() over(partition by t.ordrnbr order by s.N)) as ordrnbr,
    t.vehiclename,
    t.description,
    t.id,
    t.totprice,
    coalesce(s.Nval, t.totprice) as ind_price
from test t
    left join suffixes s on s.ordrnbr = t.ordrnbr
where
    s.Nval>=10000 or (s.Nval is null and totPrice >= 10000)

Лично я бы, вероятно, сначала отфильтровал массив и избегал группировки + объединения. Вы можете увидеть пример этого подхода ниже, но в чисто полярном решении.

Полярное решение

  • .str.split() для разделения description на список.
  • .list.gather_every(), чтобы получить все четные элементы списка.
  • .list.eval() , element() и .filter() для фильтрации элементов >= 10000
  • int_ranges() для создания индекса для элементов списка (так что WITH ORDINALITY дает вам результаты после следующей операции).
  • .list.explode() для преобразования списка в строки.
(
    test.with_columns(
        pl.col.description
        .str.split('@')
        .list.gather_every(2, 1)
        .list.eval(
            pl.element().filter(
                pl.element().cast(pl.Float64) >= 10000
            )
        ).alias('ind_price')
    )
    .filter(
        (pl.col.ind_price.list.len() > 0) | (pl.col.totprice >= 10000)
    )
    .with_columns(N = pl.int_ranges(pl.col.ind_price.list.len()))
    .explode('ind_price', 'N')
    .with_columns(
        pl.concat_str(pl.col.ordrnbr, pl.lit('-'), pl.col.N.fill_null(0) + 1),
        pl.col.ind_price.cast(pl.Float64).fill_null(pl.col.totprice)
    )
    .drop('N')
)

У меня есть таблица dbfiddle.uk/YlaNkbJN, которая будет читаться как фрейм данных Polars. Здесь, если описание не содержит разделителя, то есть @, то следует учитывать соответствующий столбец totprice, а если оно меньше 10000, то его необходимо отфильтровать, в противном случае к ordrnbr должен быть добавлен префикс -1, -2, -3 соответственно. Я попробовал описанный выше полярный способ, и для Hubseqnbr он имеет нулевое значение, а txnamt также имеет нулевое значение, и аналогично для двух других столбцов. Я использую pl.Float64, поскольку значения разделителей могут содержать десятичные значения. Можете ли вы помочь мне в этом?

Balaji Venkatachalam 19.06.2024 00:56

@BalajiVenkatachalam Я обновил ответ

Roman Pekar 19.06.2024 17:50

Для решения Duck Db все, что нам нужно сделать, это заменить (t.nr - 1)/2 на (t.nr - 1) // 2, поскольку оператор деления в Duckdb представлен как //. Спасибо за решение Polars.

Balaji Venkatachalam 20.06.2024 01:45

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