У меня есть набор данных, в котором будет несколько записей для поля столбца id
, сгруппированных по другим столбцам. Для этого набора данных я хочу создать новый столбец только для последней записи каждой группы. Я использовал case statement
для получения нового столбца и union
, чтобы получить значение для последней записи. Я думал избежать использования UNION
, поскольку это дорогостоящая операция в spark-sql
.
Ввод:
person_id order_id order_ts order_amt
1 1 2020-01-01 10:10:10 10
1 2 2020-01-01 10:15:15 15
2 3 2020-01-01 10:10:10 0
2 4 2020-01-01 10:15:15 15
Из введенных выше данных person_id 1 имеет два заказа (1,2), а person_id 2 - два заказа (3,4). Я хочу получить столбец только для последнего заказа для данного человека.
Ожидаемый результат:
person_id order_id order_ts order_amt valid_order
1 1 2020-01-01 10:10:10 10 N
1 2 2020-01-01 10:15:15 15 Y
2 3 2020-01-01 10:10:10 0 N
2 4 2020-01-01 10:15:15 15 Y
Я попытался получить результат, используя UNION
в запросе:
select person_id, order_id, order_ts, order_amt, valid_order
from
(
select *, row_number() over(partition by order_id order by derive_order) as rnk
from
(
select person_id, order_id, order_ts, order_amt, 'N' as valid_order, 'before' as derive_order
from ips_core.test_table
UNION
select person_id, order_id, order_ts, order_amt,
case when order_amt is not null and order_amt >0 then 'Y' else 'N' end as valid_order,
'after' as derive_order
from
(
select *, row_number() over(partition by person_id order by order_ts desc) as rnk
from ips_core.test_table
) where rnk = 1
) final
) where rnk = 1 order by person_id, order_id;
Я также получил тот же результат, используя комбинация left outer join
и inner join
.
Запрос соединения:
select final.person_id, final.order_id, final.order_ts, final.order_amt,
case when final.valid_order is null then 'N' else final.valid_order end as valid_order
from
(
select c.person_id, c.order_id, c.order_ts, c.order_amt, d.valid_order from ips_core.test_table c
left outer join
(
select a.*, case when a.order_amt is not null and a.order_amt >0 then 'Y' else 'N' end as valid_order
from ips_core.test_table a
inner join
(
select person_id, max(order_id) as order_id from ips_core.test_table group by 1
) b on a.person_id = b.person_id and a.order_id = b.order_id
) d on c.order_id = d.order_id
) final order by person_id, order_id;
Наш входной набор данных будет содержать около 20 миллионов записей. Есть ли более оптимизированный способ получить тот же результат, кроме приведенных выше запросов.
Любая помощь приветствуется.