微信公众号搜"智元新知"关注
微信扫一扫可直接关注哦!

查询以查找每年的活跃天数以查找每位用户每年的收入

如何解决查询以查找每年的活跃天数以查找每位用户每年的收入

我有 2 个维度表和 1 个事实表,如下所示:

user_dim

user_id 用户名 user_joining_date
1 史蒂夫 2013-01-04
2 亚当 2012-11-01
3 约翰 2013-05-05
4 托尼 2012-01-01
5 2010-01-01
6 亚历克斯 2019-01-01
7 2019-01-01

bundle_dim

bundle_id bundle_name bundle_type bundle_cost_per_day
101 电影和电视 主要 5.5
102 电视和体育 主要 6.5
103 烹饪 主要 7
104 体育和新闻 主要 5
105 儿童电影 额外 2
106 儿童教育 额外 3.5
107 西班牙新闻 额外 2.5
108 西班牙电视和体育 额外 3.5
109 旅游 额外 2

plans_fact

user_id bundle_id bundle_start_date bundle_end_date
1 101 2019-10-10 2020-10-10
2 107 2020-01-15 (空)
2 106 2020-01-15 2020-12-31
2 101 2020-01-15 (空)
2 103 2020-01-15 2020-02-15
1 101 2020-10-11 (空)
1 107 2019-10-10 2020-10-10
1 105 2019-10-10 2020-10-10
4 101 2021-01-01 2021-02-01
3 104 2020-02-17 2020-03-17
2 108 2020-01-15 (空)
4 102 2021-01-01 (空)
4 103 2021-01-01 (空)
4 108 2021-01-01 (空)
5 103 2020-01-15 (空)
5 101 2020-01-15 2020-02-15
6 101 2021-01-01 2021-01-17
6 101 2021-01-20 (空)
6 108 2021-01-01 (空)
7 104 2020-02-17 (空)
7 103 2020-01-17 2020-01-18
1 102 2020-12-11 (空)
2 106 2021-01-01 (空)
7 107 2020-01-15 (空)

注意:NULL bundle_end_date 指的是活动订阅

用户活跃天数可以计算为:bundle_end_date - bundle_start_date(对于给定的捆绑包) 每个用户的总收入可以计算为:total no. of active days * bundle rate per day

我希望编写一个查询来查找每位用户每年产生的收入。

以下是我对每位用户的总体收入的了解:

select pf.user_id,sum(datediff(day,pf.bundle_start_date,coalesce(pf.bundle_end_date,getdate())) * bd.price_per_day) total_cost_per_bundle
from plans_fact pf
inner join bundle_dim bd on bd.bundle_id = pf.bundle_id
group by pf.user_id
order by pf.user_id;

解决方法

您需要一个“年份”表来帮助将每个跨多年的行解析为单独的年份。对于每一年,您还需要重新计算开始和结束日期。这就是我在下面代码的 yearParsed cte 中所做的。我将年份硬编码到创建 y 的连接语句中。您可能会采用不同的方法,但无论您如何获得这些值,这些值都会起作用。

在那之后,与您之前所做的差不多,只是将年份列添加到您的分组中。

除此之外,我所做的只是将空合并逻辑移到 cte 以使整体逻辑更简单。

with yearParsed as (

    select      pf.*,y.year,startDt = iif(pf.bundle_start_date > y.startDt,pf.bundle_start_date,y.startDt),endDt = iif(ap.bundle_end_date < y.endDt,ap.bundle_end_date,y.endDt)
    from        plans_fact pf
    cross apply (select bundle_end_date = isnull(pf.bundle_end_date,getdate())) ap
    join        (values 
                    (2019,'2019-01-01','2019-12-31'),(2020,'2020-01-01','2020-12-31'),(2021,'2021-01-01','2021-12-31')
                ) y (year,startDt,endDt)
                    on pf.bundle_start_date <= y.endDt
                    and ap.bundle_end_date >= y.startDt

) 

select      yp.user_id,yp.year,total_cost_per_bundle = sum(datediff(day,yp.startDt,yp.endDt) * bd.bundle_cost_per_day) 
from        yearParsed yp
join        bundle_dim bd on bd.bundle_id = yp.bundle_id
group by    yp.user_id,yp.year
order by    yp.user_id,yp.year;

现在,如果这很常见,您可能应该为“年份”表创建一个基表。但是,如果它不常见,但对于此报告,您不想继续返回将年份信息硬编码到 y 表中,您可以这样做:

declare @yearTable table (
    year int,startDt char(10),endDt char(10)
);

with y as (

    select      year = year(min(pf.bundle_start_date))
    from        @plans_fact pf

    union all
    select      year + 1
    from        y 
    where       year < year(getdate())

)

insert      @yearTable
select      year,startDt = convert(char(4),year) + '-01-01',endDt = convert(char(4),year) + '-12-31'
from        y;

它会为您创建合适的年份。但是,如果您经常有这种或类似的需求,您就会明白为什么创建基表可能是首选。

版权声明:本文内容由互联网用户自发贡献,该文观点与技术仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 dio@foxmail.com 举报,一经查实,本站将立刻删除。

相关推荐


Selenium Web驱动程序和Java。元素在(x,y)点处不可单击。其他元素将获得点击?
Python-如何使用点“。” 访问字典成员?
Java 字符串是不可变的。到底是什么意思?
Java中的“ final”关键字如何工作?(我仍然可以修改对象。)
“loop:”在Java代码中。这是什么,为什么要编译?
java.lang.ClassNotFoundException:sun.jdbc.odbc.JdbcOdbcDriver发生异常。为什么?
这是用Java进行XML解析的最佳库。
Java的PriorityQueue的内置迭代器不会以任何特定顺序遍历数据结构。为什么?
如何在Java中聆听按键时移动图像。
Java“Program to an interface”。这是什么意思?