我有一组非常详细的数据:
CustomerId char(6)
Points int
PointsDate date
使用示例数据,例如:
000021 0 01-JAN-2014
000021 10 02-JAN-2014
000021 20 03-JAN-2014
000021 30 06-JAN-2014
000021 40 07-JAN-2014
000021 10 12-JAN-2014
000034 0 04-JAN-2014
000034 40 05-JAN-2014
000034 20 06-JAN-2014
000034 40 08-JAN-2014
000034 60 10-JAN-2014
000034 80 21-JAN-2014
000034 10 22-JAN-2014
因此,PointsDate
组件不一致,也不连续(它基于某些"活动"发生)
我试图为每个客户获得积分和积极差异的总量,正负变化的数量,以及最大值和最小值...但是忽略了客户的第一个实例 - 总是零。
e.g。
CustomerId Pos Neg Count(pos) Count(neg) Max Min
000021 40 30 3 1 40 10
000034 100 90 4 2 80 10
...但我没有一个线索如何实现这个目标!
我会把它放在一个立方体中,但是a)只有一个表而没有其他参考文献和b)我对立方体几乎一无所知!
答案 0 :(得分:3)
问题可以在常规TSQL中解决,其中包含一个公共表表达式,该表达式对每个客户的行进行编号,以及将每行与前一行进行比较的外部自联接;
WITH cte AS (
SELECT customerid, points,
ROW_NUMBER() OVER (PARTITION BY customerid ORDER BY pointsdate) rn
FROM mytable
)
SELECT cte.customerid,
SUM(CASE WHEN cte.points > old.points THEN cte.points - old.points ELSE 0 END) pos,
SUM(CASE WHEN cte.points < old.points THEN old.points - cte.points ELSE 0 END) neg,
SUM(CASE WHEN cte.points > old.points THEN 1 ELSE 0 END) [Count(pos)],
SUM(CASE WHEN cte.points < old.points THEN 1 ELSE 0 END) [Count(neg)],
MAX(cte.points) max,
MIN(cte.points) min
FROM cte
JOIN cte old
ON cte.rn = old.rn + 1
AND cte.customerid = old.customerid
GROUP BY cte.customerid
使用SQL Server 2012更广泛的分析功能可以稍微简化查询。
答案 1 :(得分:1)
类似于Joachim Isaksson的方法,但在CTE
中有更多工作,而在主要查询上则更少
WITH A AS (
SELECT c.CustomerID, c.Points, c.PointsDate
, Diff = c.Points - l.Points
, l.PointsDate lPointsDate
FROM Customer c
CROSS APPLY (SELECT TOP 1
Points, PointsDate
FROM Customer cu
WHERE c.CustomerID = cu.CustomerID
AND c.PointsDate > cu.PointsDate
ORDER BY cu.PointsDate Desc) l
)
SELECT CustomerID
, Pos = SUM(Diff * CAST(Sign(Diff) + 1 AS BIT))
, Neg = SUM(Diff * (1 - CAST(Sign(Diff) + 1 AS BIT)))
, [Count(pos)] = SUM(0 + CAST(Sign(Diff) + 1 AS BIT))
, [Count(neg)] = SUM(1 - CAST(Sign(Diff) + 1 AS BIT))
, Max(Points) [Max], Min(Points) [Min]
FROM A
GROUP BY CustomerID
删除第一天的条件是JOIN
中的CROSS APPLY
(CTE
):前一天没有前一天,因此会被过滤掉。
在主要查询中,我不是使用CASE
来过滤正面和负面的差异,而是首选SIGN
函数:
Sign(Diff) + 1
移动值意味着新的返回值为0,1和2 CAST
位压缩为0
为负,1
为零或为正。 0 +
定义中的[Count(pos)]
创建隐式转换为整数值BIT
无法求和。
1 -
到SUM
和COUNT
的负差异相当于NOT
:它将BIT SIGN
的值反转为1表示负数,0表示零表示积极的。
答案 2 :(得分:0)
我将从上面复制我的评论:我对立方体一无所知,但听起来你正在寻找的只是一个光标,不是吗?我知道每个人都讨厌游标,但这是我知道比较连续行而不将其加载到客户机上的最佳方式(这显然更糟)。
我看到你在回复我时提到你可以将它设置为隔夜运行,所以如果你愿意接受这种表现,我绝对认为光标将是最容易和最快的。实行。如果这只是你在这里或那里做的事情,我肯定会这样做。这是没有人最喜欢的解决方案,但它可以完成任务。
不幸的是,是的,在1200万条记录中,你肯定会花一些时间来优化你的光标。我经常使用一个大小相同的数据库,我只能想象它需要多长时间。虽然根据您的使用情况,您可能希望根据用户进行过滤,在这种情况下,光标将更容易编写,我怀疑您将面对足够的记录来导致很多问题。例如,您可以查看前20位用户并测试他们的记录,然后根据需要执行更多操作。