代码之家  ›  专栏  ›  技术社区  ›  BrynJ

MySQL高级查询智能摘要

  •  3
  • BrynJ  · 技术社区  · 15 年前

    我被要求创建一份财务报告,需要为几个“推荐人”提供两个日期之间的总佣金率。这是最简单的部分。

    困难的是,佣金率不仅取决于推荐人,而且取决于推荐人。 关于转诊的类型 而且 关于给定引用者所做的该类型的引用数。

    对转介数量的跟踪需要考虑所有转介,而不是给定日期范围内的转介-换句话说,每个转介的佣金率都在不断下滑,随着转介总数的增加而变化。幸运的是,每种类型的推荐最多只有3个佣金水平。

    所有引用都存储在同一个表中,每个引用一行,字段表示引用和引用类型。举例说明:

    ID   Type    Referrer    Date
    1    A       X           01/12/08
    2    A       X           15/01/09
    3    A       X           23/02/09
    4    B       X           01/12/08
    5    B       X           15/01/09
    6    A       Y           01/12/08
    7    A       Y           15/01/09
    8    B       Y           15/01/09
    9    B       Y           23/02/09
    

    佣金率不存储在推荐表中,而且可能会发生变化,而是存储在推荐表中,如下所示:

    Referrer    Comm_A1    Comm_A2    Comm_A3    Comm_B1    Comm_B2    Comm_B3
    X           30         20         10         55         45         35
    Y           45         35         25         60         40         30
    

    以上述转介表为例,假设转介1号和2号后的佣金率水平有所上升(然后保持不变),2008年12月至2009年2月的佣金报告将返回以下内容:

    [编辑] -为了澄清上述情况,每种类型和每个推荐人的佣金率有三个级别,第一个推荐人的佣金率为初始佣金率a1,第二个推荐人的佣金率a2,所有后续推荐人的佣金率a3。

    Referrer    Type_A_Comm    Type_A_Ref    Type_B_Comm    Type_B_Ref
    X           60             3             100            2
    Y           80             2             100            2
    

    仅在2009年2月发布一份委员会报告将返回:

    Referrer    Type_A_Comm    Type_A_Ref    Type_B_Comm    Type_B_Ref
    X           10             1             0              0
    Y           0              0             40             1
    

    编辑 以上结果已根据我的原始问题,根据列/行分组进行了调整。

    我非常肯定任何解决方案都会涉及到子查询(可能是针对每种引用类型)和某种聚合/求和if-但是我很难想出一个有效的查询。

    [编辑] 我不确定是否要写一个符合我要求的方程式,但我会列出我看到的步骤:

    确定每种类型和每个引用的以前引用的数量-即,不考虑任何日期范围。

    根据以前转介的数量,选择适当的佣金级别-0 previous=级别1,1 previous=级别2,2或更多previous=级别3

    (注:没有推荐人但有3个新推荐人的推荐人,预计佣金为1 x 1级,1 x 2级,1 x 3级=总佣金)

    根据日期范围筛选结果-以便确定某一活动期间的应付佣金。

    返回包含引用者列的数据,以及包含每个引用类型的总佣金的列(理想情况下,也是包含每个引用类型的计数的列)。

    这有助于澄清我的要求吗?

    3 回复  |  直到 12 年前
        1
  •  4
  •   Adam Robinson    15 年前

    假设您有一个名为 type 它列出了您的特定引用类型,这应该有效(如果不有效,您可以用另一个子选项来替代,以便从引用中获得不同的类型)。

    select
        r.referrer,
        t.type,
        (case 
            when isnull(ref_prior.referrals, 0) < @max1 then 
                (case 
                    when isnull(ref_prior.referrals, 0) + isnull(ref_period.referrals, 0) < @max1 then isnull(ref_period.referrals, 0) 
                    else @max1 - isnull(ref_prior.referrals, 0) 
                end) 
            else 0 
        end) * (case t.type when 'A' then r.Comm_A1 when 'B' then r.Comm_B1 else null end) +
        (case when isnull(ref_prior.referrals, 0) + isnull(ref_period.referrals, 0) > @max1 then
            (case 
                when isnull(ref_prior.referrals, 0) < @max2 then 
                    (case 
                        when isnull(ref_prior.referrals, 0) + isnull(ref_period.referrals, 0) < @max2 then isnull(ref_period.referrals, 0) 
                        else @max2 - isnull(ref_prior.referrals, 0) 
                    end) 
                else 0 
            end) -
            (case 
                when isnull(ref_prior.referrals, 0) < @max1 then 
                    (case 
                        when isnull(ref_prior.referrals, 0) + isnull(ref_period.referrals, 0) < @max1 then isnull(ref_period.referrals, 0) 
                        else @max1 - isnull(ref_prior.referrals, 0) 
                    end) 
                else 0 
            end)
        else 0 end) * (case t.type when 'A' then r.Comm_A2 when 'B' then r.Comm_B2 else null end) +
        (case when isnull(ref_prior.referrals, 0) + isnull(ref_period.referrals, 0) > @max2 then
            (isnull(ref_period.referrals, 0)) -
                (
                    (case when isnull(ref_prior.referrals, 0) + isnull(ref_period.referrals, 0) > @max1 then
                        (case 
                            when isnull(ref_prior.referrals, 0) < @max2 then 
                                (case 
                                    when isnull(ref_prior.referrals, 0) + isnull(ref_period.referrals, 0) < @max2 then isnull(ref_period.referrals, 0) 
                                    else @max2 - isnull(ref_prior.referrals, 0) 
                                end) 
                            else 0 
                        end) -
                        (case 
                            when isnull(ref_prior.referrals, 0) < @max1 then 
                                (case 
                                    when isnull(ref_prior.referrals, 0) + isnull(ref_period.referrals, 0) < @max1 then isnull(ref_period.referrals, 0) 
                                    else @max1 - isnull(ref_prior.referrals, 0) 
                                end) 
                            else 0 
                        end)
                    else 0 end) +
                    (case 
                        when isnull(ref_prior.referrals, 0) < @max1 then 
                            (case 
                                when isnull(ref_prior.referrals, 0) + isnull(ref_period.referrals, 0) < @max1 then isnull(ref_period.referrals, 0) 
                                else @max1 - isnull(ref_prior.referrals, 0) 
                            end) 
                        else 0 
                    end)
                )                   
        else 0 end) * (case t.type when 'A' then r.Comm_A3 when 'B' then r.Comm_B3 else null end) as Total_Commission
    
    from referrer r
    
    join type t on 1 = 1 --intentional cartesian product
    left join (select referrer, type, count(1) as referrals from referral where date < @start_date group by referrer, type) ref_prior on ref_prior.referrer = r.referrer and ref_prior.type = t.type
    left join (select referrer, type, count(1) as referrals from referral where date between @start_date and @end_date group by referrer, type) ref_period on ref_period.referrer = r.referrer and ref_period.type = t.type
    

    假设你有一个 @start_date @end_date 变量,显然您必须提供case语句中缺少的逻辑,以便根据ref_total中引用的类型和数量正确选择费率。

    编辑

    在回顾了这个问题之后,我看到了关于滑动比例的评论。这大大增加了查询的复杂性,但它仍然可行。修改后的查询现在还取决于两个变量的存在。 @max1 @max2 ,表示可归入类别“1”和类别“2”的最大销售额(出于测试目的,我分别使用了1和2,它们产生了预期的结果)。

        2
  •  2
  •   Jon Hopkins    15 年前

    亚当的回答比我想的要彻底得多,但我认为把它写成一个查询可能不是正确的方法。

    是否考虑过创建一个存储过程,该存储过程将逐步创建并填充一个临时表。

    临时表将具有您要查找的结果集的形状。初始插入将创建基本数据集(基本上是要用键标识符返回的行数,然后是要返回的任何其他行数,这些行数可以很容易地作为同一查询的一部分进行组装)。

    然后对临时表进行一系列更新,以组装更复杂数据的每个部分。

    最后,将其全部选回并删除临时表。

    这样做的好处是,它可以让你在脑海中把它分解,然后一次组装一点,这样你就可以更容易地发现哪里出了问题。这也意味着更复杂的钻头可以分几个阶段组装。

    此外,如果出现了一些可怜的SOD,而且事后必须调试整个系统,那么他就更容易追踪到底发生了什么。

        3
  •  0
  •   Arjan    15 年前

    编辑:这个答案没有考虑到下面的要求,但似乎有一堆新的解释,所以我想我会把它留在这里。

    跟踪转介的数量需要考虑所有转介,而不是给定日期范围内的转介。

    好的,假设报告周期是每月一次,并且使用一个实际的if可以区分两个有效的费率(对于count=1和count>1),那么:

    select
      ref.month, 
      ref.referrer, 
      ref.type,
      ( ref.count * 
          case ref.type
            when 'A' then
              case ref.count
                -- not useful: when 0 then com.Comm_A1
                when 1 then com.Comm_A2
                else com.Comm_A3
              end case
            when 'B' then
              case ref.count
                -- not useful: when 0 then com.Comm_B1
                when 1 then com.Comm_B2
                else com.Comm_B3
              end case
          end case 
      ) as total_commission
    from
      ( select
          date_format(date, '%Y-%m') as month,
          referrer,
          type,
          count(*) as count
        from referrals
        group by month, referrer, type
      ) as ref,
    join commissions com on com.referrer = ref.referrer
    

    (我想像“ref”和“count”这样的名字在上面选择得不太好。)