我有一个看起来像这样的表:
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 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;
换句话说,您只想购买紧随其后的“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
试试这个
;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
您可以使用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'
这是另一种方法......很多方法可以给这只猫留下皮肤。
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