В настоящее время я использую 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?
Любая помощь будет оценена, пожалуйста.
Решение 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)
Лично я бы, вероятно, сначала отфильтровал массив и избегал группировки + объединения. Вы можете увидеть пример этого подхода ниже, но в чисто полярном решении.
Полярное решение
description
на список.>= 10000
WITH ORDINALITY
дает вам результаты после следующей операции).(
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')
)
@BalajiVenkatachalam Я обновил ответ
Для решения Duck Db все, что нам нужно сделать, это заменить (t.nr - 1)/2 на (t.nr - 1) // 2, поскольку оператор деления в Duckdb представлен как //. Спасибо за решение Polars.
У меня есть таблица dbfiddle.uk/YlaNkbJN, которая будет читаться как фрейм данных Polars. Здесь, если описание не содержит разделителя, то есть @, то следует учитывать соответствующий столбец totprice, а если оно меньше 10000, то его необходимо отфильтровать, в противном случае к ordrnbr должен быть добавлен префикс -1, -2, -3 соответственно. Я попробовал описанный выше полярный способ, и для Hubseqnbr он имеет нулевое значение, а txnamt также имеет нулевое значение, и аналогично для двух других столбцов. Я использую pl.Float64, поскольку значения разделителей могут содержать десятичные значения. Можете ли вы помочь мне в этом?