选择聚合中的第一行和最后一行,并在SQL中创建2列

时间:2019-05-25 08:03:25

标签: sql sql-server

我正在尝试编写一个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

如何选择聚合中的第一行和最后一行,并创建其中的两列?

3 个答案:

答案 0 :(得分:2)

由于您具有同一日期的最大和最小购买日期(客户ID = 10),所以如果第一列是我估计具有自动增量的ID,则可以使用以下脚本获得所需的输出-

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 :(得分:1)

这里是使用COUNTROW_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;

答案 2 :(得分:1)

不幸的是,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 distinctexists

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;

如果您想从每个订单中获取多个值,这实际上是最方便的方法-除了产品外,还说金额,付款方式和日期。