Объедините функции окна В первую и последнюю очередь

#sql #pyspark

Вопрос:

Есть ли более простой способ использовать функции окна первого и последнего значения, чем выводить первое и последнее значения из CTE/таблиц/подзапросов, а затем объединять по ключу?

Пример игрушки ниже. На самом деле мой набор данных велик и находится в hadoop с большим количеством записей и полей.

Для каждого клиента я хочу видеть, какой первый товар они купили (указывается приращением числа покупок), а также последний товар_оригина.

«source_table» в приведенном ниже примере запроса.

идентификатор пользователя номер покупки пункт item_origin
0001 1 мяч Огайо
0001 2 бумага Техас
0001 3 ручка Канзас
0002 1 ручка Канзас
0003 1 бумага Техас
0004 2 фрисби Флорида

Если бы это была полная таблица, результат должен быть:

идентификатор пользователя first_item last_item_оригин
0001 мяч Канзас
0002 ручка Канзас
0003 бумага Флорида

Вот как я сейчас это реализую, но это кажется немного надуманным.

 WITH min_max AS (
SELECT 
    customer_id,
    MIN(purchase_number) AS min_row, 
    MAX(purchase_number) AS max_row 
FROM 
    source_table
GROUP BY 
    customer_id

),
min_ AS (
SELECT
    a.*
FROM
    source_table a
    JOIN min_max b
        ON a.customer_id = b.customer_id
        AND a.purchase_number = b.min_row
),
max_ AS (
SELECT
    a.*
FROM
    source_table a
    JOIN min_max b
        ON a.customer_id = b.customer_id
        AND a.purchase_number = b.max_row
)

SELECT
    a.customer_id,
    a.item,
    b.item_origin
FROM
    min_ a
    JOIN max_ b
        ON a.customer_id = b.customer_id
 

Ответ №1:

Просто используйте условную агрегацию и оконные функции:

 select customer_id,
       max(case when seqnum = 1 then item end) as first_item,
       max(case when seqnum_desc = 1 then item_origin end) as last_item_origin
from (select s.*,
             row_number() over (partition by customer_id order by purchase_number) as seqnum,
             row_number() over (partition by customer_id order by purchase_number desc) as seqnum_desc
      from source_table s
     ) s
group by customer_id;