Выберите первую строку и последнюю строку в агрегации и создайте 2 столбца в SQL - PullRequest
1 голос
/ 25 мая 2019

Я пытаюсь написать запрос SQL, который показывает для каждого клиента, совершившего две или более покупки, просмотр первого и последнего приобретенного продукта:

custumerID   | Product ID First purchase | Product ID Last purchase
    10       |            286            |            448
   1033      |            244            |            138
    11       |            265            |            299

Мне удалось показать все купленные клиенты, совершившие две или более покупок, ProductID и дату:

SELECT Customer_ID, Order_Date, Product_ID
FROM Orders
WHERE Customer_ID IN 
(SELECT Customer_ID FROM Orders
GROUP BY Customer_ID
HAVING COUNT(*) >= 2)
ORDER BY Customer_ID, (CONVERT(datetime,Order_Date))

enter image description here

Как выбрать первую и последнюю строки в агрегации и создать из них 2 столбца?

Ответы [ 3 ]

2 голосов
/ 25 мая 2019

Поскольку у вас МАКСИМАЛЬНАЯ и МИН. Дата покупки на одну и ту же дату (идентификатор клиента = 10), если в первом столбце указан идентификатор, который, как я полагаю, с автоинкрементом, вы можете использовать следующий скрипт для желаемого результата:

SELECT 
Customer_ID,
(SELECT Order_ID FROM your_table WHERE ID =MIN(A.ID)) [Product ID First purchase],
(SELECT Order_ID FROM your_table WHERE ID=MAX(A.ID)) [Product ID Last purchase]
FROM your_table A
GROUP BY Customer_ID
1 голос
/ 25 мая 2019

К сожалению, SQL Server (пока?) Не поддерживает «первую» и «последнюю» функции как функции агрегирования. Он поддерживает их как оконные функции, поэтому вы можете сделать:

select distinct customer_id,
       first_value(product_id) over (partition by customer_id order by order_date asc) as first_product,
       first_value(product_id) over (partition by customer_id order by order_date desc) as last_product
from orders o
where exists (select 1
              from orders o2
              where o2.customer_id = o.customer_id and
                    o2.order_date <> o.order_date
             );

Или, если вам нравятся оконные функции, вы можете обойтись без select distinct и exists:

select customer_id, first_product, last_product
from (select o.*,
            first_value(product_id) over (partition by customer_id order by order_date asc) as first_product,
            first_value(product_id) over (partition by customer_id order by order_date desc) as last_product,
            count(*) over (partition by customer_id) as cnt,
            row_number() over (partition by customer_id order by order_date) as seqnum
    ) o
where cnt >= 2 and seqnum = 1;

Я бы сформулировал условную агрегацию следующим образом:

select o.customer_id,
       max(case when seqnum_asc = 1 then o.product_id end) as first_product,
       max(case when seqnum_desc = 1 then o.product_id end) as last_product
from (select o.*,
             row_number() over (partition by customer_id order by order_date asc) as seqnum_asc,
             row_number() over (partition by customer_id order by order_date desc) as seqnum_desc
      from orders o
     ) o
group by customer_id
having count(*) >= 2;

Традиционный метод неоконной функции будет использовать два соединения:

select o.customer_id,
       firsto.product_id as first_product,
       lasto.product_id as last_product
from (select customer_id, min(order_date) as min_od,
             max(order_date) as max_od
      from orders o
      group by customer_id
      having count(*) >= 2
     ) o join
     orders firsto
     on firsto.customer_id = o.customer_id and
        firsto.order_date = o.min_od join
     orders lasto
     on lasto.customer_id = o.customer_id and
        last.order_date = o.max_od;

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

1 голос
/ 25 мая 2019

Вот один из способов сделать это, используя COUNT и ROW_NUMBER в качестве аналитических функций.

WITH cte AS (
    SELECT Customer_ID, Order_Date, Product_ID,
        COUNT(*) OVER (PARTITION BY Customer_ID) cnt,
        ROW_NUMBER() OVER (PARTITION BY Customer_ID ORDER BY Order_Date) rn_first,
        ROW_NUMBER() OVER (PARTITION BY Customer_ID ORDER BY Order_Date DESC) rn_last
    FROM Orders
)

SELECT
    Customer_ID,
    MAX(CASE WHEN rn_first = 1 THEN Product_ID END) AS Product_ID_first,
    MAX(CASE WHEN rn_last = 1  THEN Product_ID END) AS Product_ID_last
FROM cte
WHERE cnt >= 2
GROUP BY
    Customer_ID
ORDER BY
    Customer_ID;
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...