一个人因其推荐的朋友的购买而获得10%的佣金。
有两个表:
参考表
Person_id Referrer_id
3 1
4 1
5 1
6 2
交易表
Person_id Amount Action Date
3 100 Purchase 10-20-2011
4 200 Purchase 10-21-2011
6 400 Purchase 12-15-2011
3 200 Purchase 12-30-2011
1 50 Commision 01-01-2012
1 10 Cm_Bonus 01-01-2012
2 20 Commision 01-01-2012
如何获取Referrer_Person_id = 1
的以下ResultsetMonth Ref_Pur Earn_Comm Todate_Earn_Comm BonusRecvd Paid Due
10-2011 300 30 30 0 0 30
11-2011 0 0 30 0 0 30
12-2011 200 20 50 0 0 50
01-2012 0 0 50 10 50 0
上面使用的标签是:
Ref_Pur = Total Referred Friend's Purchase for that month
Earn_Comm = 10% Commision earned for that month
Todate_Earn_Comm = Total Running Commision earned upto that month
我写的MYSQL代码
SELECT dx1.month,
dx1.ref_pur,
dx1.earn_comm,
( @cum_earn := @cum_earn + dx1.earn_comm ) as todate_earn_comm
FROM
(
select date_format(`date`,'%Y-%m') as month,
sum(amount) as ref_pur ,
(sum(amount)*0.1) as earn_comm
from transaction tr, reference rf
where tr.person_id=rf.person_id and
tr.action='Purchase' and
rf.referrer_id=1
group by date_format(`date`,'%Y-%m')
order by date_format(`date`,'%Y-%m')
)as dx1
JOIN (select @cum_earn:=0)e;
如何加入查询还包括BonusRecvd,Paid和Due trnsactions,它们不依赖于参考表?
并且还为'11 -2011'月份生成行,即使该月没有发生过trnx
答案 0 :(得分:1)
如果要在结果中包含佣金支付和奖金,您可能需要在用于计算结果的初始数据集中包含相应的行(Action IN ('Commision', 'Cm_Bonus')
)。或者,至少,这就是我要做的,也可能是这样的:
SELECT t.Amount, t.Action, t.Date
FROM Transaction t LEFT JOIN Reference r ON t.Person_id = r.Person_id
WHERE r.Referrer_id = 1 AND t.Action = 'Purchase'
OR t.Person_id = 1 AND t.Action IN ('Commision', 'Cm_Bonus')
在计算每月SUM时,您可以使用CASE表达式来区分与不同类型的Action
相关的金额。这是查询的相应部分的外观:
…
IFNULL(SUM(CASE Action WHEN 'Purchase' THEN Amount END) , 0) AS Ref_Pur,
IFNULL(SUM(CASE Action WHEN 'Purchase' THEN Amount END) * 0.1, 0) AS Earn_Comm,
IFNULL(SUM(CASE Action WHEN 'Cm_Bonus' THEN Amount END) , 0) AS BonusRecvd,
IFNULL(SUM(CASE Action WHEN 'Commision' THEN Amount END) , 0) AS Paid
…
在计算Due
值时,您可以初始化另一个变量并使用它与@cum_earn
非常相似,除了您还需要减去Paid
,如下所示:
(@cum_due := @cum_due + Earn_Comm - Paid) AS Due
最后一个问题似乎是缺少了几个月。为解决这个问题,我会做以下几点:
从要处理的子集中获取第一个和最后一个日期(由本文开头的查询获得)。
获取每个日期的相应月份(即另一个日期仅为同月的第一个日期)。
使用数字表生成一个月份列表,涵盖上一步计算的两个月。
过滤掉要处理的子集中存在的月份,并使用剩余的月份将虚拟交易添加到子集中。
如您所见,执行这些步骤时需要触摸两次“要处理的子集”。因此,为了有效,我会将该子集插入临时表并使用该表,而不是多次执行相同(子)查询。
步骤3中提到的数字表是我建议保持随时使用的工具。如果你原谅双关语,你只需要初始化一次,它对你的用途可能会变得很多。这是填充数字表的一种方法:
CREATE TABLE numbers (n int);
INSERT INTO numbers (n) SELECT 0;
INSERT INTO numbers (n) SELECT cnt + n FROM numbers, (SELECT COUNT(*) AS cnt FROM numbers) s;
INSERT INTO numbers (n) SELECT cnt + n FROM numbers, (SELECT COUNT(*) AS cnt FROM numbers) s;
INSERT INTO numbers (n) SELECT cnt + n FROM numbers, (SELECT COUNT(*) AS cnt FROM numbers) s;
INSERT INTO numbers (n) SELECT cnt + n FROM numbers, (SELECT COUNT(*) AS cnt FROM numbers) s;
INSERT INTO numbers (n) SELECT cnt + n FROM numbers, (SELECT COUNT(*) AS cnt FROM numbers) s;
INSERT INTO numbers (n) SELECT cnt + n FROM numbers, (SELECT COUNT(*) AS cnt FROM numbers) s;
INSERT INTO numbers (n) SELECT cnt + n FROM numbers, (SELECT COUNT(*) AS cnt FROM numbers) s;
INSERT INTO numbers (n) SELECT cnt + n FROM numbers, (SELECT COUNT(*) AS cnt FROM numbers) s;
/* repeat as necessary; every repeated line doubles the number of rows */
这似乎就是这样。我不会在这里发布完整的解决方案,以免您有机会尝试以自己的方式使用上述建议,以防您热衷于此。但是,如果您正在努力或只是想验证他们可以应用于所需的效果,您可以尝试this SQL Fiddle page以获得“实际行动”的完整解决方案。