HiveSQL题——array_contains函数

目录

一、原创文章被引用次数

0 问题描述

1 数据准备

2 数据分析

​编辑

3 小结

二、学生退费人数

0 问题描述

1 数据准备

2 数据分析

3 小结

一、原创文章被引用次数

0 问题描述

   求原创文章被引用的次数,注意本题不能用关联的形式求解。

1 数据准备

   id表示文章id,oid表示引用的其他文章id,当oid为0时表示当前文章为原创文章。

create table if not exists  table18
(
    id    int comment '文章id',
    oid   int comment '引用的其他文章id'
) comment '文章信息表';

insert overwrite table table18 values
(1,0),
(2,0),
(3,1),
(4,1),
(5,2),
(6,0),
(7,3);

2 数据分析

    题目要求的是原创文章被引用的次数,其中原创文章为oid等于0的文章,即求解文章id为【1,2,6】被引用的次数。常见的思路是用关联方式求解,具体SQL如下图所示:

思路一:用左连接 left join 


--思路一:用左连接 left join 
select
    t1.id,
    count(t2.oid) as cnt
from (select * from table18 where oid = 0) t1
         left join
         (select * from table18 where oid <> 0) t2
         on t1.id = t2.oid
group by t1.id
order by t1.id;

 输出结果为:

 题意要求不能使用join等关联形式求解,其实该题本质是存在性计数问题

思路二:借助array_contains(array,element) 函数

select
    new_id,
    sum(flag)as cnt
from (
         select
             id,
             oid,
             contains,
             -- 第二步:利用array_contains()函数判断引用的oid是否在原创文章id集合中,ture则记为1,false则记为0
             if(array_contains(contains, oid), 1, 0)    flag,
             -- 第三步:清洗数据,补充完整的原创文章
             if(array_contains(contains, oid), oid, if(oid = 0, id, null)) new_id
         from ( -- 第一步:构建原创文章id集合,作为辅助列
                  select
                      id,
                      oid,
                      collect_set(if(oid = 0, id, null)) over () contains
                  from table18
              ) tmp1
     ) tmp2
where new_id is not null
group by new_id;

    上述代码解析:通过array_contains(array,column) 函数进行存在性检测,如果array中包含column 则记为1,不存在记为0,关键公式: sum(if(array_contains(array,column),1,0))

上述代码解析:

第一步:构建原创文章id集合contains,将contains作为辅助列。

  select
        id,
        oid,
        collect_set(if(oid = 0, id, null)) over () contains
from table18;

第二步:利用array_contains()函数,判断非原创的oid是否在原创文章id集合中,存在则计数为1,否则计数为0。

select
        id,
        oid,
        contains,
        if(array_contains(contains, oid), 1, 0) as flag
from ( 
         select
               id,
               oid,
               collect_set(if(oid = 0, id, null)) over () contains
          from table18
      ) tmp1;

第三步:清洗数据,对原创文章id补充完整

select
        id,
        oid,
        contains,
        if(array_contains(contains, oid), 1, 0)   flag,
      --清洗数据,对原创文章id补充完整
        if(array_contains(contains, oid), oid, if(oid = 0, id, null)) new_id
from ( 
          select
               id,
               oid,
               collect_set(if(oid = 0, id, null)) over () contains
          from table18
       ) tmp1;

 

   ps: 此处需要对原创文章id补充完整,否则会丢失记录。具体是:通过array_contains(contains,oid)去判断,代码为 if(array_contains(contains, oid), oid, if(oid = 0, id, null)) as  new_id   -->  代表的意思是如果oid存在于原创文章id构建的集合中,就取得该oid,如果不存在,再判断oid是否为0,如果是0,则取得id,否则记为null。

第四步:将new_id 为null的数据滤掉,并对new_id分组,求出各原创文章被引用的次数sum(flag)as cnt

select
    new_id,
    sum(flag)as cnt
from (
         select
             id,
             oid,
             contains,
             -- 第二步:利用array_contains()函数判断引用的oid是否在原创文章id集合中,ture则记为1,false则记为0
             if(array_contains(contains, oid), 1, 0)    flag,
             -- 第三步:清洗数据,补充完整的原创文章id
             if(array_contains(contains, oid), oid, if(oid = 0, id, null)) new_id
         from ( -- 第一步:构建原创文章id集合,作为辅助列
                  select
                      id,
                      oid,
                      collect_set(if(oid = 0, id, null)) over () contains
                  from table18
              ) tmp1
     ) tmp2
  -- 第四步:将为null的数值过滤掉,并对new_id分组,求出各原创文章被引用的次数sum(flag)as cnt
where new_id is not null
group by new_id;

3 小结

 上述例子中利用array_contains(array,column)进行存在性检测,如果存在则记为1,不存在则记为0,核心计算公式为 sum(if(array_contains(array,value),1,0))

二、学生退费人数

0 问题描述

求截止当前月的学生退费总人数【当月的学生退费人数:上月存在,这月不存在的学生个数】。

1 数据准备

create table if not exists test19( dt string comment '日期',
stu_id string comment '学生id');

insert overwrite table test19
values ('2020-01-02','1001'),
       ('2020-01-02','1002'),
       ('2020-02-02','1001'),
       ('2020-02-02','1002'),
       ('2020-02-02','1003'),
       ('2020-02-02','1004'),
       ('2020-03-02','1001'),
       ('2020-03-02','1002'),
       ('2020-04-02','1005'),
       ('2020-05-02','1006');

2 数据分析

完整的代码如下:

select month,
      sum(month_cnt) over(order by month) as result
from(
    select month,
           lag(next_month_cnt,1,0) over(order by month) as month_cnt
    from(
        select distinct 
               t0.month as month,
               sum(if(!array_contains(t1.lead_stu_id_arr,t0.stu_id),1,0)) over(partition by t0.month) as next_month_cnt
        from
            (select 
                  date_format(dt,'yyyy-MM') as month,
                  stu_id
            from test19) t0
        left join
        (
            select month,
                   lead(stu_id_arr,1) over(order by month) as lead_stu_id_arr
            from(
                 select date_format(dt,'yyyy-MM') as month,
                        collect_list(stu_id) as stu_id_arr
                 from test19
                 group by date_format(dt,'yyyy-MM') 
                ) tmp1
        ) t1
        on t0.month = t1.month
    ) tmp2
) tmp3;

第一步:聚合每个月的stu_id,利用collect_list()函数(不去重)合并,具体sql如下:

select date_format(dt,'yyyy-MM') as month,
       collect_list(stu_id) as stu_id_arr
from test19
group by date_format(dt,'yyyy-MM') 

计算结果如下:

2020-01	[1001,1002]
2020-02	[1001,1002,1003,1004]
2020-03	[1001,1002]
2020-04	[1005]
2020-05	[1006]

第二步:按照月份排序,获取下一月合并之后的值,sql如下:

 select month,
        stu_id_arr,
        lead(stu_id_arr,1) over(order by month) as lead_stu_id_arr
from(
       select
                date_format(dt,'yyyy-MM') as month,
                collect_list(stu_id) as stu_id_arr
       from test19
       group by date_format(dt,'yyyy-MM')
     ) tmp1;

计算结果如下:

2020-01	[1001,1002]	[1001,1002,1003,1004]
2020-02	[1001,1002,1003,1004]	[1001,1002]
2020-03	[1001,1002]	[1005]
2020-04	[1005]	[1006]
2020-05	[1006]	NULL

     ps:总体思路是利用数组差集函数求出差值集合后,再利用size()求出具体的个数,最后sum聚合即可。hive中的数组函数array_contains可以实现这个需求,该函数表示在数组中查询某个元素是否存在。在该题目中,借助此函数判断 当月某个学生id是否在下月(数据集合 -->数组)中存在,如果存在就为0,不存在标记为1。

 第三步:利用步骤2的结果与原表进行关联,获取当前学生id

select
    t0.*,
    t1.*
from (select
          date_format(dt, 'yyyy-MM') as month,
          stu_id
      from test19) t0
 left join ( select
                   month,
                   lead(stu_id_arr, 1) over (order by month) as lead_stu_id_arr
             from ( select
                          date_format(dt, 'yyyy-MM') as month,
                          collect_list(stu_id)       as stu_id_arr
                  from test19
                  group by date_format(dt, 'yyyy-MM')
                 ) tmp1
             ) t1
on t0.month = t1.month;

结果如下:

2020-01	1001	2020-01	[1001,1002,1003,1004]
2020-01	1002	2020-01	[1001,1002,1003,1004]
2020-02	1001	2020-02	[1001,1002]
2020-02	1002	2020-02	[1001,1002]
2020-02	1003	2020-02	[1001,1002]
2020-02	1004	2020-02	[1001,1002]
2020-03	1001	2020-03	[1005]
2020-03	1002	2020-03	[1005]
2020-04	1005	2020-04	[1006]
2020-05	1006	2020-05	NULL

第四步:利用array_contains()函数判断当月的stu_id是否在下个月array数组中,如果存在标记0,不存在标记1。具体sql如下:

        select t0.month,
               t0.stu_id,
              if(!array_contains(t1.lead_stu_id_arr,t0.stu_id),1,0) as flag
        from
            (select
                   date_format(dt,'yyyy-MM') as month,
                   stu_id
            from test19) t0
        left join
        (
            select month,
                   lead(stu_id_arr,1) over(order by month) as lead_stu_id_arr
            from(
                 select date_format(dt,'yyyy-MM') as month,
                        collect_list(stu_id) as stu_id_arr
                 from test19
                 group by date_format(dt,'yyyy-MM')
                ) tmp1
        ) t1
        on t0.month = t1.month

结果如下:

2020-01	1001	0
2020-01	1002	0
2020-02	1001	0
2020-02	1002	0
2020-02	1003	1
2020-02	1004	1
2020-03	1001	1
2020-03	1002	1
2020-04	1005	1
2020-05	1006	1

第五步:基于步骤四的结果,按照月份分组,对flag求和,得到下个月的学生退费人数

select  distinct t0.month,
       -- 求解下个月的退费人数
        sum(if(!array_contains(t1.lead_stu_id_arr,t0.stu_id),1,0)) over(partition by t0.month) as next_month_cnt
from  (select
             date_format(dt,'yyyy-MM') as month,
             stu_id
       from test19) t0
left join
        ( select month,
                 lead(stu_id_arr,1) over(order by month) as lead_stu_id_arr
          from( select 
                        date_format(dt,'yyyy-MM') as month,
                        collect_list(stu_id) as stu_id_arr
                 from test19
                 group by date_format(dt,'yyyy-MM')
                ) tmp1
        ) t1
on t0.month = t1.month;

计算结果如下:

注意:第二列求是下个月的退费人数。

2020-01	0
2020-02	2
2020-03	2
2020-04	1

第六步:计算当前月的退费人数

    步骤五计算的是下一个月的学生退费人数,再利用 lag(next_month_cnt,1,0) over(order by month) 向上偏移一行,就得到当前月的退费人数

sql代码如下:

select month, 
      --基于下月的退费人数month_cnt字段,向上偏移一行,就得到当前月的退费人数
       lag(next_month_cnt,1,0) over(order by month) as month_cnt
 from(
        select distinct t0.month as month,
               sum(if(!array_contains(t1.lead_stu_id_arr,t0.stu_id),1,0)) over(partition by t0.month) as next_month_cnt
        from
            (select
                  date_format(dt,'yyyy-MM') as month,
                  stu_id
            from test19) t0
        left join
        (
            select month,
                   lead(stu_id_arr,1) over(order by month) as lead_stu_id_arr
            from(
                 select date_format(dt,'yyyy-MM') as month,
                        collect_list(stu_id) as stu_id_arr
                 from test19
                 group by date_format(dt,'yyyy-MM')
                ) tmp1
        ) t1
        on t0.month = t1.month
    ) tmp2;

计算结果如下:

2020-01	0
2020-02	0
2020-03	2
2020-04	2
2020-05	1

计算截止到当前月的退费人数,sql代码如下:

select month,
       -- sum() over(order by ..) 窗口计算范围:上无边界(起始行)到当前行
       sum(month_cnt) over(order by month) as result
from(
    select month,
          lag(next_month_cnt,1,0) over(order by month) as month_cnt
    from(
        select distinct t0.month as month,
               sum(if(!array_contains(t1.lead_stu_id_arr,t0.stu_id),1,0)) over(partition by t0.month) as next_month_cnt
        from
            (select
                  date_format(dt,'yyyy-MM') as month,
                  stu_id
            from test19) t0
        left join
        (
            select month,
                   lead(stu_id_arr,1) over(order by month) as lead_stu_id_arr
            from(
                 select date_format(dt,'yyyy-MM') as month,
                        collect_list(stu_id) as stu_id_arr
                 from test19
                 group by date_format(dt,'yyyy-MM')
                ) tmp1
        ) t1
        on t0.month = t1.month
    ) tmp2
) tmp3;

计算结果为:

2020-01	0
2020-02	0
2020-03	2
2020-04	4
2020-05	5

3 小结

   针对存在性问题,一般的求解思路是:1.利用collect_set()或者 collect_list()函数进行聚合,将数据集转换成数据组。2.再利用array_contains()等函数判断集合(数组)中是否存在某元素,针对结果打上标签。3.再根据标签进行之后的分组聚合计算等。

ps:以上文章参考:

https://blog.csdn.net/godlovedaniel/article/details/119388498?ops_request_misc=%257B%2522request%255Fid%2522%253A%2522167921970316800184142859%2522%252C%2522scm%2522%253A%252220140713.130102334..%2522%257D&request_id=167921970316800184142859&biz_id=0&utm_medium=distribute.pc_search_result.none-task-blog-2~all~sobaiduend~default-1-119388498-null-null.142^v74^control_1,201^v4^add_ask,239^v2^insert_chatgpt&utm_term=%E5%AD%98%E5%9C%A8%E6%80%A7%E9%97%AE%E9%A2%98&spm=1018.2226.3001.4187文章浏览阅读741次。本文对存在性问题进行了探讨和研究,此类问题往往需要对不同的记录做对比分析,我们可以先将符合条件的数据域按照collect_set()或collect_list()函数进行聚合转换成数组,然后获取历史的数据域放入当前行,最后利用hive中数组的相关处理手段进行对比分析。常用的hive数组处理函数如expode()、size()、array()、array_contains()等函数,本题就借助于hive ,array_contains()函数进行存在性问题分析。_sql 求截止当前月退费总人数https://blog.csdn.net/godlovedaniel/article/details/119388498?ops_request_misc=%257B%2522request%255Fid%2522%253A%2522167921970316800184142859%2522%252C%2522scm%2522%253A%252220140713.130102334..%2522%257D&request_id=167921970316800184142859&biz_id=0&utm_medium=distribute.pc_search_result.none-task-blog-2~all~sobaiduend~default-1-119388498-null-null.142%5Ev74%5Econtrol_1,201%5Ev4%5Eadd_ask,239%5Ev2%5Einsert_chatgpt&utm_term=%E5%AD%98%E5%9C%A8%E6%80%A7%E9%97%AE%E9%A2%98&spm=1018.2226.3001.4187

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mfbz.cn/a/371919.html

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

本次安装Visual Studio 所用的安装程序不完整。请重新运行VisualStudio安装程序以解决此问题

今天点开VS的时候遇到了这个问题 因为昨天升级到一半电脑关机了&#xff0c;今天打开软件遇到如下错误&#xff0c; 解决办法很简单&#xff0c;找到安装目录进入Installer文件夹 我的目录在C:\Program Files (x86)\Microsoft Visual Studio\Installer 找到vs_installer.exe…

idea修改项目git地址

大家好&#xff0c;今天给大家分享的知识是如何在idea中修改项目的git地址。 一、修改地址 首先我们先找到菜单栏中Git选项&#xff0c;然后点击管理远程&#xff08;Manage Remote&#xff09; 之后双击origin之后就可以定义名称或者URL了。

oracle主库增加redo组数

redo log&#xff08;重做日志&#xff09;&#xff1a; 重做日志&#xff1a;简单来说就是&#xff0c;将oracle数据库的DML、DDL&#xff08;数据库操作语言&#xff0c;数据库定义i语言&#xff09;操作记录在日志中&#xff0c;方便恢复及备库使用&#xff0c;以组的方式管…

《Lua程序设计》-- 学习11

反射&#xff08;Re fl ection&#xff09; 反射是程序用来检查和修改其自身某些部分的能力 调试库由两类函数组成&#xff1a;自省函数&#xff08;introspective function&#xff09;和钩子&#xff08;hook&#xff09;。自省函数允许我们检查一个正在运行中的程序的几个…

【实训】网络系统集成课程实训(vlan、vrrp、nat)

目录 一 实训概述 1.1 实训目的 1.2 实训内容 二 实训原理 2.1 VLAN间划分及VLAN间通信 2.2 BGP&#xff0c;边界网关协议 BGP是运行于 TCP 上的一种自治系统的路由协议&#xff0c;用于在AS之间实现路由信息的交互。 2.2.1 VRRP原理 2.2.2 OSPF配置 三&#xff0e;实训…

docker重建镜像

DockerFile如下&#xff1a; FROM k8s-registry.qhtx.local/base/centos7-jdk8-haitong0704RUN yum -y update && yum install -y python3-devel && yum install -y python36 RUN mv /usr/bin/python /usr/bin/python_old RUN ln -s /usr/bin/python3 /usr/bi…

我用JVS低代码平台,搭建了一套固定资产管理系统

随着企业规模的不断扩大和业务的快速发展&#xff0c;资产管理成为了企业运营中的重要环节。然而&#xff0c;传统的手工管理模式已经无法满足现代企业的需求&#xff0c;管理效率低下、信息不准确、流程不规范等问题逐渐凸显。为了解决这些问题&#xff0c;越来越多的企业开始…

将xyz格式的GRACE数据转成geotiff格式

我们需要将xyz格式的文件转成geotiff便于成图&#xff0c;或者geotiff转成xyz用于数据运算&#xff0c;下面介绍如何实现这一操作&#xff0c;采用GMT和matlab两种方法。 1.GMT转换 我们先准备一个xyz文件&#xff0c;这里是一个降水文件。在gmt中采用以下的语句实现xyz转grd…

Java栈和队列

&#x1f435;本文章将对栈相关知识进行讲解 一、什么是栈 栈是一种特殊的线性表&#xff0c;向栈中放入元素的次序是由栈底到栈顶依次放入&#xff0c;被称为入栈或压栈&#xff0c;从栈中出元素时只能从栈顶出&#xff0c;被称为出栈。即栈要求元素“先进后出” 下面给一道经…

Vivado-IP核

Vivado-IP核 主程序 timescale 1ns / 1ps ////module ip_clk_wiz(input sys_clk,input sys_rst_n,output clk_out1,output clk_out2,output clk_out3,output clk_out4,output locked);clk_wiz_0 instance_name(// Clock out ports.clk_out1(clk_out1), // output clk_out…

ywtool login guard命令

一.登录防护功能介绍 登录防护功能主要检查系统日志/var/log/secure&#xff0c;查看系统有没有被暴力登录。登录防护默认是检测3分钟内登录系统失败15次(次数可修改)后,视其为有攻击性,拉黑此IP(centos7通过系统文件阻止IP,centos8/9通过防火墙阻止IP)。此脚本只针对SSH访问,…

layui

基于复杂结构的自定义模版相关介绍 我这里的接口给的格式数据 我这里搜索往返时候要显示成这样的 layui.use([table,form], function(){ var table layui.table; var form layui.form;// 渲染表格 table.render({ elem: #test-table-reload,toolbar: #toolbarDemo, …

【Python基础】seaborn 使用指南(超详细!)

文章目录 seaborn1 seaborn简介1.1 主要特征&#xff1a;1.2 seaborn主要内容 2 seaborn基本设置2.1 图表大小&#xff1a;context2.2 设置风格2.3 设置字体与支持中文2.4 设置临时风格2.5 设置调色板2.6 set方法 3 调色板3.1 分类色板&#xff08;qualitative&#xff09;3.2 …

3.0 Hadoop 概念

本章着重介绍 Hadoop 中的概念和组成部分&#xff0c;属于理论章节。如果你比较着急可以跳过。但作者不建议跳过&#xff0c;因为它与后面的章节息息相关。 Hadoop 整体设计 Hadoop 框架是用于计算机集群大数据处理的框架&#xff0c;所以它必须是一个可以部署在多台计算机上…

chisel RegInit/UInt/U

val reg RegInit(0.U(8.W)) //ok val reg RegInit(0.UInt(8.W)) //errU 使用在数字 . 后边50.U UInt 使用在IO(new Bundle val a Input(UInt(8.W)) 或者 def counter(max:UInt, a1:UInt) package emptyimport chisel3._ import chisel3.util._class MyCounter extends …

Java技术栈 —— Hive与HBase

Java技术栈 —— Hive与HBase 一、 什么是Hive与HBase二、如何使用Hive与HBase&#xff1f;2.1 Hive2.1.1 安装2.1.2 使用2.1.2.1 使用前准备2.1.2.2 开始使用hive 2.2 HBase2.2.1 安装2.2.2 使用 三、Apache基金会 一、 什么是Hive与HBase 见参考文章。 一、参考文章或视频链…

神经网络激活函数到底是什么?

激活函数 其实不是很难啦&#xff0c;归结一下就是大概这样几个分类&#xff0c;详情请参考【神经网络】大白话直观理解&#xff01;_哔哩哔哩_bilibili神经网络就是干这个事的~ 如果队伍不长&#xff0c;一个ykxb就可以了&#xff0c;如果 如果 队伍太长 就加一个激活函数也…

C语言函数递归详解

递归是什么&#xff1f; 递归&#xff0c;顾名思义&#xff0c;就是递推和回归。 递归是一种解决问题的方法&#xff0c;在C语言中&#xff0c;递归就是函数自己调用自己。 #include <stdio.h> int main() {printf("hehe\n");main();//main函数中⼜调⽤了main…

C++ 调用lua 脚本

需求&#xff1a; 使用Qt/C 调用 lua 脚本 扩展原有功能。 步骤&#xff1a; 1&#xff0c;工程中引入 头文件&#xff0c;库文件。lua二进制下载地址&#xff08;Lua Binaries&#xff09; 2&#xff0c; 调用脚本内函数。 这里调用lua 脚本中的process函数&#xff0c;并…

FFMPEG推流到B站直播

0、参考 ffmpeg安装参考小弟另外的一个博客&#xff1a;FFmpeg和rtsp服务器搭建视频直播流服务-CSDN博客推流参考&#xff1a;用ffmpeg 做24小时推流直播_哔哩哔哩_bilibili 一、获取b站直播码 点击开始直播后&#xff0c;会出现以下的画面 二、ffmpeg进行直播推流 ffmpeg -r…