SQL SERVER OVER PARTITION 业务案例
Posted
技术标签:
【中文标题】SQL SERVER OVER PARTITION 业务案例【英文标题】:OVER PARTITION BY SQL SERVER Business case 【发布时间】:2015-06-12 09:31:07 【问题描述】:我需要一些帮助来解决一个问题。我在 SQL SERVER 2012 工作。基本上是这样的:
客户可以购买三种产品:
-
一个
B
C
如果客户在同一天,我们应该将其显示为“Dual”。
如果客户在同一天只购买了一件产品,那么我们应该称其为“单件”。
如果客户在同一天购买了所有三种产品,我们应该称之为“Triple”。
这是我的数据目前的样子:
YearMonth Product CustomerNr Sales Date
201505 B 70056844 20150501
201505 A 70056844 20150501
201505 B 70057297 20150503
201505 A 70057494 20150504
201505 B 70057494 20150504
201505 C 70057494 20150504
201505 B 70033055 20150506
201505 B 36021632 20150508
201505 A 70060612 20150508
201505 C 70060612 20150508
正如我们在示例数据中看到的,客户编号:70060612 在同一销售日期购买了两种产品 A 和 C,因此我们可以说他购买了双包装。客户编号:70057494 在同一销售日期购买了 3 种产品,A、B 和 C。我们可以称之为 Triple。
我希望我的数据包含这样的列:
YearMonth Product CustomerNr Sales Date Package
201505 B 70056844 20150501 Dual
201505 A 70056844 20150501 Dual
201505 B 70057297 20150503 Single
201505 A 70057494 20150504 Triple
201505 B 70057494 20150504 Triple
201505 C 70057494 20150504 Triple
201505 B 70033055 20150506 Single
201505 B 36021632 20150508 Single
201505 A 70060612 20150508 Dual
201505 C 70060612 20150508 Dual
我该怎么做?我正在考虑做一些类似的事情
Test=COUNT(*) OVER (PARTITION BY CustomerNr)
【问题讨论】:
有一个“教科书示例”,使用您提到的方法。 MSDN 看例子B。 【参考方案1】:这是一个带有相应数据示例的解决方案。希望这对您有所帮助。
create table #t(dt datetime, prod char(1), customer int)
declare @date datetime = getdate()
insert into #t(dt,prod,customer)
values(@date,N'A',1),(@date,N'A',1),(@date,N'C',1),(@date,N'B',2),(@date,N'C',2),(@date,N'B',3),(@date,N'A',3),(@date,N'A',4),(@date,N'B',5),(@date,N'C',6),
(@date,N'A',7),(@date,N'B',7),(@date,N'C',7)
SELECT dt,prod,customer, MAX(cntDay) OVER(PARTITION BY customer, dt) as cntDay,
CASE MAX(cntDay) OVER(PARTITION BY customer, dt)
WHEN 2 THEN N'Dual'
WHEN 3 THEN N'Triple'
ELSE N'Single' END as package -- Your Case
FROM (
SELECT *, DENSE_RANK() OVER(PARTITION BY customer, dt ORDER BY prod) as cntDay
FROM #t
) as dat
ORDER BY customer, dt -- just for a better overview
drop table #t
最好的问候,离子
【讨论】:
您没有考虑实现单一、双重或三重销售所需的不同组合。您的解决方案会将同一客户在同一天对 A 的 2 次销售计为双重销售。 更正了演示。感谢您的提示。现在计数正确。【参考方案2】:不幸的是 SQL 不允许 COUNT(Distinct) OVER
,DENSE_RANK()
是一种解决方法
DECLARE @Table table
(
id int identity(1,1) primary key,
YearMonth int,
Product char(1),
CustomerNr int,
SalesDate date
)
INSERT @Table VALUES
(201505, 'B', 70056844, '20150501'),
(201505, 'A', 70056844, '20150501'),
(201505, 'B', 70057297, '20150503'),
(201505, 'A', 70057494, '20150504'),
(201505, 'B', 70057494, '20150504'),
(201505, 'C', 70057494, '20150504'),
(201505, 'B', 70033055, '20150506'),
(201505, 'B', 36021632, '20150508'),
(201505, 'A', 70060612, '20150508'),
(201505, 'C', 70060612, '20150508'),
(201505, 'A', 70056844, '20150501') -- Additional for duplicated product
SELECT
*,
CASE
DENSE_RANK() OVER (PARTITION BY CustomerNr, SalesDate ORDER BY Product)
+ DENSE_RANK() OVER (PARTITION BY CustomerNr, SalesDate ORDER BY Product DESC) - 1
WHEN 1 THEN 'Single'
WHEN 2 THEN 'Dual'
WHEN 3 THEN 'Triple'
ELSE 'Multiple' -- Not defined case
END AS Package
FROM
@Table
ORDER BY
id
结果
id YearMonth Product CustomerNr SalesDate Package
----------- ----------- ------- ----------- ---------- --------
1 201505 B 70056844 2015-05-01 Dual
2 201505 A 70056844 2015-05-01 Dual
3 201505 B 70057297 2015-05-03 Single
4 201505 A 70057494 2015-05-04 Triple
5 201505 B 70057494 2015-05-04 Triple
6 201505 C 70057494 2015-05-04 Triple
7 201505 B 70033055 2015-05-06 Single
8 201505 B 36021632 2015-05-08 Single
9 201505 A 70060612 2015-05-08 Dual
10 201505 C 70060612 2015-05-08 Dual
11 201505 A 70056844 2015-05-01 Dual
【讨论】:
我有一个问题。很好,你带了重复的行,ID 11。如果客户在同一天购买了 ID 2 和 ID 11,并且购买了相同的产品,但每个产品 (A) 的服务 ID 不同,怎么能限制让我仅在特定日期为每个产品提取一行客户编号?示例 no 应提取产品 A 的两行。每天每个产品只能一行。 @user3197575 是的,您始终可以在计算Package
类型之前过滤表。 SELECT MIN(id) id, MIN(SalesDate) SalesDate, YearMonth, Product, CustomerNr FROM @Table GROUP BY YearMonth, Product, CustomerNr
以上是关于SQL SERVER OVER PARTITION 业务案例的主要内容,如果未能解决你的问题,请参考以下文章
SQL Server 10.50 OVER PARTITION 无法识别
SQL Server Rank() Over Partition w/Back and Forth 值