当前位置: 首页 > article >正文

SQL进阶:如何跳过多个NULL值取第一个非NULL值?

NULL

  • 一、问题描述
  • 二、ORACLE
    • <一>、last_value () over ()
    • <二>、lag () over()
    • <三>、相关子查询
  • 三、MYSQL
    • <一>、全局变量
    • <二>、coalesce() + lag() over()
    • <三>、相关子查询
    • <四>、 recursive
    • <五>、lag() over() + min() over() / max() over()

一、问题描述

  • 假如某张表中某个列有多个null值,如何跳过这多个null值取第一个不为空的值去填充,如下述表格所示
productsale_daeamount
12024/01/01100
12024/01/02200
12024/01/03
12024/01/04
22024/01/01200
22024/01/02
22024/01/03300
22024/01/04

某产品当天sale_date为空的销售价格取上一天的填充,最终想展示的如下述表格所示

productsale_daeamount
12024/01/01100
12024/01/02200
12024/01/03200
12024/01/04200
22024/01/01200
22024/01/02200
22024/01/03300
22024/01/04300

二、ORACLE

<一>、last_value () over ()

  • last_value()是sql中的一个窗口函数,用于获取窗口中的最后一个值,默认计算范围是第一行到当前行,有窗口是窗口内的第一行到当前行
select product,
	   sale_date,
	   amount,
	   last_value(amount ignore nulls)over(partition by product order by sale_date) as last_amount
  from test
  • 如上述代码所示,按照产品分组,销售日期排序,若是有值则自己就是组内的最后一个值,把自己填充,若为NULL,则用IGNORE NULLS语法忽略NULL值,则用上一个值填充

<二>、lag () over()

  • lag()也是sql中的窗口,用于获取当前行的前几条记录,默认为上一条记录
select product,
	   sale_date,
	   amount,
	   coalsece(amount,lag(amount ignore nulls)over(partition by product order by sale_date)) as last_amount
  from test

如上述代码所示,按照产品分组,销售日期排序,用了coalesce()函数,表示若是amount为空,则取lag(),默认是取上一条,上一条若也为空,则用IGNORE NULLS语法忽略NULL值,再取上一个填充,直到找到非NULL值

<三>、相关子查询

select product,
	   sale_date,
	   amount,
	   (select  amount
	     from (
			select amount 
			  from test t1 
			 where t1.product = t.product
			   and t1.sale_date <= t.sale_date
			   and amount is not null 
			 order by t1.sale_date desc
			) 
		where rownum <= 1) as last_amount
  from test t
  • 用一个内部的子查询找到product相同,日期<=当前日期,且amount不为空的第一条

三、MYSQL

  • MYSQL中虽然也有last_value()和lag()函数,但是不支持IGNORE NULLS选项,所以不能够直接用这两个函数实现

<一>、全局变量

  • mysql中@表示全局变量,可以用全局变量递归实现
set @last_non_null := NULL;

with tmp as (
	selet product,
	      sale_date,
	      amount,
	      if(amount is null, @last_non_null := coalesce(@last_non_null,amount),
	      @last_non_null := amount) as last_amount
	 from test
    order by product,sale_date
)
	select product,
	       sale_date,
	       amount,
	       cast(last_amount as float) as last_amount
	  from tmp
  • 如上述代码所示,order by
    product,sale_date是保证同个产品是按照sale_date排序的,也就是按照产品分组,销售日期排序
  • set @last_non_null : NULL表示设置全局变量last_non_null为NULL,后面的sql会用到这个变量
  • amount不为空的时候,last_non_null直接赋值amount返回;当amount为空的时候,last_non_null此时没有被赋值,直接返回,返回的就是上一个非空值

<二>、coalesce() + lag() over()

  • 上面说到Mysql的lag() over()是不支持ignore nulls选项的,那如何实现忽略null值呢?可以用一种笨方法,就是前面几条都写出来
select product,
	   sale_date,
	   amount,
	   coalesce(amount,
			lag(amount,1)over(partition by product order by sale_date),
			lag(amount,2)over(partition by product order by sale_date),
			lag(amount,3)over(partition by product order by sale_date),
			...
		)
  from test
  • 上述方法可以适用于连续NULL值比较少的情况,如果连续NULL值比较多,还是不建议的

<三>、相关子查询

  • Mysql的相关子查询和Oracle逻辑是一样的,只不过取第一条的时候稍有不同,mysql是用limit
select product,
       sale_date,
       amount,
       (select amount
         from test t1
        where t1.product = t.product
          and t1.sale_date <= t.sale_date 
        order by t1.sale_date desc
        limit 1) as last_amount
  from test

<四>、 recursive

<五>、lag() over() + min() over() / max() over()

  • 这个方法比较特殊化,不是所有场景都适用,主要针对一些有序的场景,比如上述例子针对日期amount都是有序的,可以将它当做一种思路
with tmp as (
	select product,
	       sale_date,
	       amount,
	       lag(amount) over (partition by product order by sale_date) as last_amount
	  from test
)
	select product,
	       sale_date,
	       amount,
	       coalesce(amount,max(amount)over(partition by product order by sale_date)) as last_amount
	  from tmp

http://www.kler.cn/a/410816.html

相关文章:

  • [每日一氵] 拆分 pip install git+https://github.com/xxx/xx.git@bece3d4
  • ARM CCA机密计算安全模型之概述
  • Java项目实战II基于微信小程序的图书馆自习室座位预约平台(开发文档+数据库+源码)
  • 计算机网络socket编程(2)_UDP网络编程实现网络字典
  • el-table vue3统计计算数字
  • 自然语言处理: RAG优化之Embedding模型选型重要依据:mteb/leaderboard榜
  • Postgresql 获取字段里的字段内容的长度
  • linux实战-黑链——玄机靶场
  • Linux—进程概念学习-03
  • web 中 canvas 污染 以及解决方案
  • 解锁数据安全的金钥匙:商用密码在现代商业中的应用与挑战
  • 【MySQL实战45讲笔记】基础篇——行锁
  • 人工智能深度学习-Torch框架-数学运算
  • 【Android+多线程】IntentService 知识总结:应用场景 / 使用步骤 / 源码分析
  • 数据结构--创建链表--Python
  • SpringBoot中忽略实体类中的某个属性不返回给前端的方法
  • Maven 依赖管理
  • 使用llama.cpp进行量化和部署
  • 自由学习记录(23)
  • windows 中docker desktop 安装
  • uni-app自定义底部tab并且根据字段显示和隐藏
  • 设计模式——空对象模式
  • 如何不使用密码,通过ssh直接登录服务器
  • 【Python】九大经典排序算法:从入门到精通的详解(冒泡排序、选择排序、插入排序、归并排序、快速排序、堆排序、计数排序、基数排序、桶排序)
  • 第二十天 模型评估与调优
  • LeetCode 872.叶子相似的树