3

一个人从他推荐的朋友的购买中获得 10% 的佣金。

有两个表:

  1. 参考表
  2. 交易表

参考表

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 获取以下结果集

Month     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

4

1 回答 1

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

最后一个问题似乎缺少几个月。为了解决这个问题,我会做以下事情:

  1. 从要处理的子集中获取第一个和最后一个日期(通过本文开头的查询获得)。

  2. 获取每个日期的对应月份(即另一个日期,它只是同一个月的第一天)。

  3. 使用数字表,生成涵盖上一步中计算的两个月份的列表。

  4. 过滤出要处理的子集中存在的月份,并使用剩余的月份将虚拟交易添加到子集中。

如您所见,执行这些步骤时,需要触摸两次“要处理的子集”。因此,为了提高效率,我会将该子集插入到一个临时表中并使用该表,而不是多次执行相同的(子)查询。

第 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 */

似乎就是这样。我不会在这里发布完整的解决方案,以免您有机会尝试以自己的方式使用上述建议,以防您热衷于使用。但是,如果您正在苦苦挣扎或只是想验证它们是否可以应用于所需的效果,您可以尝试这个 SQL Fiddle 页面以获得“实际中”的完整解决方案。

于 2012-05-17T15:59:42.780 回答