【问题标题】:How many customers upgraded from Product A to Product B?有多少客户从产品 A 升级到产品 B?
【发布时间】:2019-04-05 17:29:13
【问题描述】:

我有一个“每日更改”表,用于记录客户“升级”或“降级”其会员级别的时间。在表格中,假设字段 1 是客户 ID,字段 2 是会员类型,字段 3 是更改日期。客户 123 和 ABC 在表中各有两行。字段 1 (ID) 中的值相同,但字段 2 (TYPE) 和字段 3 (DATE) 中的值不同。我想编写一个 SQL 查询来告诉我在任何给定时间范围内,有多少客户从会员类型 1“升级”到会员类型 2,有多少客户从会员类型 2“降级”到会员类型 1。

该表还显示了其他类型的更改。为了识别成员类型字段中发生更改的记录,我创建了以下代码:

SELECT *
FROM member_detail_daily_changes_new
WHERE customer IN (
    SELECT customer
    FROM member_detail_daily_changes_new
    GROUP BY customer
    HAVING COUNT(distinct member_type_cd) > 1)

我想看一个告诉我的结束报告:

对于 2018 财年, X,XXX 客户从会员类型 1 转移到会员类型 2,并且 X,XXX 客户从会员类型 2 转移到会员类型 1

【问题讨论】:

  • 如果客户在同一年从类型 1 更改为 2 并再次更改为 1 会发生什么?
  • 有可能。我确实看到了几行,其中一位客户在表中有三行或更多行。我想在这些情况下,我需要计算从第一行到第二行的变化以及从第二行到第三行的变化,使用日期字段来指示变化的顺序。
  • 那么同一个客户将同时计入两个类别?
  • 好问题。我想我想为同一个客户捕捉这两个动作。所以是的,他会被算作一次升级和一次降级。
  • 如果其他人想随意使用创建的DEMO 来模拟答案!无需在测试数据上重新发明轮子!

标签: sql ssrs-2012


【解决方案1】:

听起来是使用 LEAD() 分析函数提前查找给定客户的 member_Type 的好时机;将其与当前记录进行比较,然后评估这是否是升级/降级,然后总结结果。 DEMO

CTE AS (SELECT case when lead(Member_Type_Code) over (partition by Customer order by date asc) > member_Type_Code then 1 else 0 end as Upgrade
             , case when lead(Member_Type_Code) over (partition by Customer order by date asc) < member_Type_Code then 1 else 0 end as DownGrade
FROM member_detail_daily_changes_new
WHERE Date between '20190101' and '20190201')

SELECT sum(Upgrade) upgrades, sum(downgrade) downgrades
FROM  CTE

给我们:使用我的样本数据

+----+----------+------------+
|    | upgrades | downgrades |
+----+----------+------------+
|  1 |        3 |          2 |
+----+----------+------------+

我不确定 rex 测试仪上的 SQL express 是否不支持分析本身的 sum() 这就是我必须添加 CTE 的原因,或者这也是非 SQL express 版本中的规则。

其他一些注意事项:

  • 我让系统在 where 子句中隐式转换日期
  • 我假设 member_Type_Code 本身会告诉我这是升级还是降级,这从长远来看可能是不正确的。假设我们添加了会员类型 3,它介于 1 和 2 之间……现在是什么……所以也许我们需要在 Member_Type_Code 之外的十进制数字,以便我们可以处理未来的会员资格,以及它是升级/降级还是横向.. .
  • 我假设所有升级/降级都被计算在内,如果成员在所需的时间段内经常发生变化,则可以多次计算一个用户。
  • 我假设升级/降级不能在同一日期/时间发生。否则铅的分类可能无法正常工作。 (但如果它是时间戳字段,我们不应该有问题)

那么这是如何工作的呢?

我们使用公用表表达式 (CTE) 生成每个客户所需的降级/升级评估。这也可以在派生表中在线完成,但我发现 CTE 更易于阅读;然后我们总结一下。

Lead(Member_Type_Code) over (partition by customer order by date asc) 执行以下操作

它按客户组织数据,然后按日期升序排序。

因此,我们最终会在按日期排序的后续行中获得所有相同的客户记录。 Lead(field) 然后从记录 1 开始,并为同一客户展望记录 2,并在记录 1 上返回记录 2 的 Member_Type_Code。然后我们可以比较这些类型代码并确定是否发生了升级或降级。然后,我们能够对比较结果求和并提供所需的总数。

现在我们对一个非常小的查询有一个冗长的解释:P

【讨论】:

  • 将测试/试用并报告。谢谢。
  • 我在测试它时不得不做一些更正。更新以反映这些更改,并提供了使用 rextester 的示例演示
  • 我还添加了许多 cmets 来帮助解释正在发生的事情以及对它的假设和想法。
【解决方案2】:

您想为此使用lag(),但您需要注意日期过滤。所以,我想你想要:

SELECT prev_membership_type, membership_type,
       COUNT(*) as num_changes,
       COUNT(DISTINCT member) as num_members
FROM (SELECT mddc.*,
             LAG(mddc.membership_type) OVER (PARTITION BY mddc.customer_id ORDER BY mddc.date) as prev_membership_type
      FROM member_detail_daily_changes_new mddc
     ) mddc
WHERE prev_membership_type <> membership_type AND
      date >= '2018-01-01' AND
      date < '2019-01-01'
GROUP BY membership_type, prev_membership_type;

注意事项:

  • date 上的过滤需要在lag() 的计算之后发生
  • 这考虑到会员在2017年可能有某种类型,然后在2018年换成新类型。
  • 日期过滤与索引兼容。
  • 计算了两个值。一是变化的总数。对于每种类型的更改,另一个只计算每个成员一次。

【讨论】:

    【解决方案3】:

    自加入表后进行条件聚合:

    select 
      2018 fiscal, 
      sum(case when m.member_type_cd > t.member_type_cd then 1 else 0 end) upgrades, 
      sum(case when m.member_type_cd < t.member_type_cd then 1 else 0 end) downgrades 
    from member_detail_daily_changes_new m inner join member_detail_daily_changes_new t
    on 
      t.customer = m.customer 
      and 
      t.changedate = (
        select max(changedate) from member_detail_daily_changes_new
        where customer = m.customer and changedate < m.changedate
      )
    where year(m.changedate) = 2018 
    

    即使有超过 2 种类型的会员级别,这也会起作用。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 2018-06-24
      • 2021-03-17
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多