在最近一次购买之前选择最近的购买

问题描述 投票:3回答:5

我有一个看起来像这样的表:

customer_id  purchase_date  category
1            9/1/2018       Electronics
1            9/2/2018       Art
1            9/3/2018       Books
1            9/5/2018       CPG
2            9/2/2018       Books
2            9/4/2018       Electronics
2            9/20/2018      CPG     

从这里开始,我试图在购买CPG之前获得最近的购买。为了进一步解释,这是我的步骤:

步骤1.创建不在CPG类别中的购买表:

WITH OTHERS AS(
    SELECT customer_id,
           category as others_category,
           purchase_date
    FROM orders o
    WHERE category IN ('Electronics', 'Books', 'Art')
),

步骤2.在CPG类别中创建购买表:

CPG AS( 
    SELECT customer_id,
           category as cpg_category,
           purchase_date
    FROM orders o
    WHERE category = 'CPG'
)

第3步。左连接:这是我被卡住的地方。我想在购买CPG之前制作一张最近购买的OTHER表。即,输出应如下所示:

others_category  count_distinct_customers
Electronics            1
Books                  1

理想情况下,我不想使用CTE。 SQL类型是SQL Server 2017。

sql sql-server sql-server-2017
5个回答
1
投票

这就是我在SQL Server 2017中的表现,但是,我不确定这是否会在2005年运行(不幸的是,就像我说的,我没有2005测试环境了)。我认为APPLY是在SQL Server 2008中添加的。当然,“VTE”在2005年将不起作用,因为VALUES构造函数条款是在2008年添加的(如果我没记错的话),但是,你将有一个表来测试最小:

WITH VTE AS(
    SELECT V.customer_id,
           CONVERT(date,V.purchase_date,101) AS purchase_date,
           V.category
    FROM (VALUES(1,'9/1/2018 ','Electronics'),
                (1,'9/2/2018 ','Art'),
                (1,'9/3/2018 ','Books'),
                (1,'9/5/2018 ','CPG'),
                (2,'9/2/2018 ','Books'),
                (2,'9/4/2018 ','Electronics'),
                (2,'9/20/2018','CPG')) V(customer_id,purchase_date,category))
SELECT V2.category,
       COUNT(DISTINCT V2.customer_id) AS DistinctCustomers
FROM VTE V1
     CROSS APPLY (SELECT TOP 1
                         customer_id,
                         purchase_date,
                         category
                  FROM VTE ca 
                  WHERE ca.customer_id = V1.customer_id
                    AND ca.purchase_date < V1.purchase_date
                  ORDER BY ca.purchase_date DESC) V2

WHERE V1.category = 'CPG'
GROUP BY V2.category;

1
投票

换句话说,您只想购买紧随其后的“CPG购买”(由同一客户?)。

分析函数LEAD()允许您查找“跟随”行中的内容,而无需将数据重新连接到自身。

WITH
  orders_with_lookup AS
(
  SELECT
    *,
    LEAD(category) OVER (PARTITION BY customer_id ORDER BY purchase_date)   AS customers_next_purchase_category
  FROM
    orders
)
SELECT
  category,
  COUNT(DISTINCT customer_id)   AS count_distinct_customers
FROM
  orders_with_lookup
WHERE
  customers_next_purchase_category = 'CPG'
GROUP BY
  category
ORDER BY
  category

0
投票

试试这个

;WITH CTE(customer_id , purchase_date , category)
AS
(
SELECT 1,'9/1/2018' ,'Electronics' UNION ALL
SELECT 1,'9/2/2018' ,'Art'         UNION ALL
SELECT 1,'9/3/2018' ,'Books'       UNION ALL
SELECT 1,'9/5/2018' ,'CPG'         UNION ALL
SELECT 2,'9/2/2018' ,'Books'       UNION ALL
SELECT 2,'9/4/2018' ,'Electronics' UNION ALL
SELECT 2,'9/20/2018','CPG'     
)
,CTE2 
AS
(
SELECT customer_id,purchase_date,category, 
       ROW_NUMBER()OVER(PARTITION BY customer_id ORDER BY purchase_date DESC) AS MostRecentPurchase
FROM
(
SELECT customer_id , 
       CAST( purchase_date AS DATE) purchase_date, 
       category
FROM CTE
)dt
)
SELECT Category AS Others_category,
       COUNT(DISTINCT customer_id) AS Count_distinct_customers
FROM  CTE2
WHERE  MostRecentPurchase = 2
GROUP BY category

结果

Others_category     Count_distinct_customers
-----------------------------------------
Books                   1
Electronics             1

0
投票

您可以使用OUTER APPLY(自SQL Server 2005以来可用)通过以前购买OTHERS来加入每个CPG订单,然后您可以返回OTHERS订单数据。

我添加了一个DISTINCT,所以如果两个CPG订单具有相同的OTHERS先前订单(因为它们之间没有输入其他订单),那么它只返回一次。

   SELECT DISTINCT others.*
   FROM orders cpg
        OUTER APPLY (SELECT top 1 others.*
                     FROM orders as others
                     WHERE category <> 'CPG' and
                           others.purchase_date < cpg.purchase_date
                           order by others.purchase_date desc) as others
   WHERE category = 'CPG'

-1
投票

这是另一种方法......很多方法可以给这只猫留下皮肤。

declare @Something table
(
    customer_id int
    , purchase_date date
    , category varchar(20)
)
insert @Something values
(1, '9/1/2018 ', 'Electronics')
, (1, '9/2/2018 ', 'Art')
, (1, '9/3/2018 ', 'Books')
, (1, '9/5/2018 ', 'CPG')
, (2, '9/2/2018 ', 'Books')
, (2, '9/4/2018 ', 'Electronics')
, (2, '9/20/2018', 'CPG')

, (3, '9/2/2018 ', 'Books') --added customer 3 
, (3, '9/4/2018 ', 'Electronics')
, (3, '9/20/2018', 'CPG')

select category
    , DistinctCustomerCount = count(*)
from
(
    select *
        , RowNum = row_number()over(partition by customer_id, case when category = 'CPG' then 1 else 0 end order by purchase_date desc)
    from @Something
) x
where x.category <> 'CPG'
    and x.RowNum = 1
group by x.category
© www.soinside.com 2019 - 2024. All rights reserved.