我有一张如下表格:
VisitorID Product VisitDayBeforePurchase
1 Product1 0
2 Product2 1
3 Product3 2
1 Product1 2
3 Product2 2
3 Product3 2
VisitorID始终是每个访问者唯一的,visitDayBeforePurchase代表他们是否在购买前x天来到网站。我想做的是制作一个可以将表格转换成这样的语句的语句。
Product Day0 Day1 Day2
Product1 1 0 1
Product2 0 1 2
Product3 0 0 2
基本上,我希望在购买特定产品前X天看到有人访问网站的平均访问次数。即访问前每天每件产品的总和(访问)/总和(uniqueVisitors)
我只是要从表1下载数据并编写一个脚本来计算,但我想知道是否有办法在SQL中执行此操作。
如果有人能指出我正确的方向,我们将不胜感激。
答案 0 :(得分:1)
对于已知数量的列,您描述的表 - 实际上不是平均值,它是计数 - 可以使用IF
来完成:
SELECT Product,
SUM(IF(VisitDayBeforePurchase = 0, 1, 0)) AS Day0,
SUM(IF(VisitDayBeforePurchase = 1, 1, 0)) AS Day1,
SUM(IF(VisitDayBeforePurchase = 2, 1, 0)) AS Day2
FROM yourtable
GROUP BY Product;
基本上,我希望在购买特定产品前X天看到有人访问网站的平均访问次数。即访问前每天每件产品的总和(访问)/总和(uniqueVisitors)
这是一个不同的请求。您可以通过添加(或替换)列
来完成此操作SELECT Product,
AVG(VisitDayBeforePurchase) AS AverageDays
FROM yourtable
GROUP BY Product;
这会给你所有(你可以看到它在行动中here)。
SELECT Product,
SUM(IF(VisitDayBeforePurchase = 0, 1, 0)) AS Day0,
SUM(IF(VisitDayBeforePurchase = 1, 1, 0)) AS Day1,
SUM(IF(VisitDayBeforePurchase = 2, 1, 0)) AS Day2,
AVG(VisitDayBeforePurchase) AS AverageDays
FROM yourtable
GROUP BY Product;
简而言之:它很复杂,也许它最好不要完成。
假设我们有一个产品被同一个访问者两次(或更多)查看,那么我们不希望将它们视为单独访问。如果先生。 X在三天,两天和购买当天访问了该网站,我们该怎么做?
乍一看,我们可能会认为只计算最后次访问。但是我们会得到明显的意外后果:因为您必须访问该网站以在网站上购买商品,然后上次访问才能购买您进行购买的访问< / em>,所以它总是在购买之前的零天。在同一时间和分钟,甚至可能。虽然可以考虑上次访问,但它会给我们带来毫无价值的结果。
考虑到第一次访问也会产生忽视重复购买的意外后果,因此我们的最佳重复客户实际上将被视为最顽固和优柔寡断。< / p>
因此,人们必须考虑,例如,只有实际用SUM表格的日间隔,然后做某事:
VisitorID ProductID VDBeforeP
42 137 3
42 137 2
41 137 2
但要做什么?如果我们只考虑访问者42的一个记录,无论我们做什么,我们最终得出的结果都是错误的,要么平均过于乐观,要么平均过于悲观。我们可以考虑用户42的平均值,对于权重 1 (而不是 2 )的用户42,它会给出2.5,所以相比之下与#34;粗暴的平均值&#34; (上面的解决方案)我们认为重复的客户少一点。
为此,我们使用SUBSELECT
:我们获取每个数据点只有一个访客和产品的平均数据
SELECT VisitorID, Product, AVG(VisitDayBeforePurchase) AS VisitDayBeforePurchase
FROM visits GROUP BY VisitorID, Product;
这将生成一个格式与原始格式相同的表格,但具有平均数据。 它永远不会起作用因为原始查询只验证了整数天数,而2.5既不是2也不是3.所以我们必须做出乐观或悲观的修正;这是乐观的
SELECT VisitorID, Product, FLOOR(AVG(VisitDayBeforePurchase)) AS VisitDayBeforePurchase
FROM visits GROUP BY VisitorID, Product;
虽然悲观会使用FLOOR(1.0+AVG...
。折衷方案是使用ROUND
。
现在我们重复查询:
SELECT Product,
SUM(IF(V = 0, 1, 0)) AS Day0,
SUM(IF(V = 1, 1, 0)) AS Day1,
SUM(IF(V = 2, 1, 0)) AS Day2,
AVG(BetterV) AS AverageDays
FROM (
SELECT VisitorID,
Product,
ROUND(AVG(VisitDayBeforePurchase)) AS V,
AVG(VisitDayBeforePurchase) AS BetterV
FROM visits GROUP BY VisitorID, Product
) AS grouped
GROUP BY Product;
<强> A working example can be also found here 强>
要在map-reduce环境中运行上述内容,您需要两个阶段:直接输出VisitorID,Product和VisitDayBeforePurchase的map阶段,以及按键分组的reduce阶段(VisitorID,Product)并输出那些和V (和BetterV?)计算结果。
这会被送到一个新的减少阶段,该阶段在V&#39上执行平均值。