如何在SQL Server中实现Ungroup操作

概要

我们经常在SQL Server中使用group by语句配合聚合函数,对已有的数据进行分组统计。本文主要介绍一种分组的逆向操作,通过一个递归公式,实现ungroup操作。

代码和实现

我们看一个例子,输入数据如下,我们有一张产品表,该表显示了产品的数量。
在这里插入图片描述
要求实现Ungroup操作,最后输出数据如下:
在这里插入图片描述

代码和实现

基本思路

要想实现ungroup,显然需要表格的自连接。自连接的次数取决于total_count的数量。

代码

自连接操作过程中涉及大量的子查询,为了便于代码后期维护,我们采用CTE。每次子查询,total_count自动减一,total_count小于0时,直接过滤掉,该数据不再参与查询。

第1轮查询

获取全部total_count 大于0的数据,即全表数据。

with cte1 as (select * from products where total_count > 0
),

输出结果:
在这里插入图片描述

第2轮查询

第2轮子查询,以第1轮的输出作为输入,进行表格自连接,total_count减1,过滤掉total_count小于0的产品。

with cte1 as (select * from products where total_count > 0
),cte2 as (select * from (select cte1.id, cte1.name, (cte1.total_count -1) as total_count from cte1join products p1 on cte1.id = p1.id) t 
where t.total_count > 0
)select * from cte2

输出结果是:
在这里插入图片描述
和第1轮相比较,输出结果中没了Flashlight了,因为它的total_count减1后为0,被过滤了。

第3轮查询

第3轮子查询,以第2轮的输出作为输入,进行表格自连接,total_count减1,过滤掉total_count小于0的产品。

with cte1 as (select * from products where total_count > 0
),cte2 as (select * from (select cte1.id, cte1.name, (cte1.total_count -1) as total_count from cte1join products p1 on cte1.id = p1.id) t 
where t.total_count > 0
),
cte3 as (select * from (select cte2.id, cte2.name, (cte2.total_count -1) as total_count from cte2join products p1 on cte2.id = p1.id) t where t.total_count > 0
)select * from cte3

输出结果如下:

在这里插入图片描述

第4轮查询

第4轮子查询,以第3轮的输出作为输入,进行表格自连接,total_count减1,过滤掉total_count小于0的产品。

with cte1 as (select * from products where total_count > 0
),cte2 as (
select * from (select cte1.id, cte1.name, (cte1.total_count -1) as total_count from cte1join products p1 on cte1.id = p1.id) t 
where t.total_count > 0
),cte3 as (select * from (select cte2.id, cte2.name, (cte2.total_count -1) as total_count from cte2join products p1 on cte2.id = p1.id) t 
where t.total_count > 0
),cte4 as (select * from (select cte3.id, cte3.name, (cte3.total_count -1) as total_count from cte3join products p1 on cte3.id = p1.id) t 
where t.total_count > 0
)select * from cte4

输出结果:

在这里插入图片描述
下一次迭代,compass的total_count也将等于0,被过滤掉,查询结果不会再有新的记录,所以查询结束。我们将cte1,cte2,cte3 和 cte4 合并,合并结果即是所求。

代码改进

显然上述代码过于冗长,如果产品数量很多,那子查询的代码也将大幅度增加。

事实上,从第2轮到第4轮的子查询,代码是非常相近的,对于这种情况,无论任何开发语言,我们都可以采用递归的方式进行优化处理。对于此类为题,递归公式如下:

with CTE as (initial query  -- 初始查询union all -- 查询结果合并recursive query -- 递归部分,即在查询中直接引用CTERecursive terminatation condition -- 递归终止条件
)

初始查询,就是我们的第1轮迭代。递归部分,就是我们所谓的相似代码部分。

对于递归终止条件,默认是如果没有新的记录参加递归,则递归终止。本例是按照业务逻辑,设置的终止条件,即total_count需要大于0,这样也可以做到过滤到最后,不会再有新的记录参与到递归中。

按照上述供述,得到的查询代码如下:

with cte as (select * from products where total_count > 0union allselect * from (select cte.id, cte.name, (cte.total_count -1) as total_count from ctejoin products p1 on cte.id = p1.id) t where t.total_count > 0
)select id, name from cte
order by id, name

当我们使用CTE时候,发现每次查询的代码类似,就可以考虑采用上述递归公式对代码进行优化。找到初始查询结果,在相似的代码中找到递归部分以及递归终止条件。

附录

建表和数据初始化代码

if OBJECT_ID('products', 'U') is not null 
drop table productscreate table  products 
(id int primary key identity(1,1),name nvarchar(50) not null,total_count int not null
)insert into products (name, total_count) values 
('Water Bottle', 3),
('Tent', 2),
('Flashlight', 1),
('compass',4)

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

如若内容造成侵权/违法违规/事实不符,请联系编程知识网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

【新版系统架构】第十七章-通信系统架构设计理论与实践

软考-系统架构设计师知识点提炼-系统架构设计师教程(第2版) 第一章-绪论第二章-计算机系统基础知识(一)第二章-计算机系统基础知识(二)第三章-信息系统基础知识第四章-信息安全技术基础知识第五章-软件工程…

【webrtc】ProcessThreadAttached

RegisterModule 调用所在的线程指针传递给ProcessThreadAttached ProcessThreadAttached 调用不是在worker thread 而是在 registers/deregister 这个module或者 start stop 这个module的时候 ** ** pacedsender是一个moudle -实现了

用Arthas快速定位线上JVM问题!

Arthas分析FullGC问题定位 对于FullGC那一定不会陌生,一般来说会采用横切FullGC前置拦截(-XX:+HeapDumpBeforeFullGC)和后置拦截(-XX:+HeapDumpAfterFullGC),导出FullGC发生前后的heap dump文件,以便于我们进行FullGC原因的分析和定位。 推测分析问题之FullGC的频率过高…

Kubernetes基础知识点

k8s可以看做是一个集群操作系统,能够对容器进行调度和编排。 Kubernetes中的基本对象 pod 是k8s中的最小单位,一个pod封装一个或者多个容器,存储资源。 deployment 是对pod的服务化封装,可以包含一个或多个pod statefulset 为…

【面试题34】什么是MVC,为什么要使用它

文章目录 一、前言二、MVC介绍2.1 模型(Model)2.2 视图(View)2.3 控制器(Controller) 三、MVC模式的优点四、总结 一、前言 本文已收录于PHP全栈系列专栏:PHP面试专区。 计划将全覆盖PHP开发领域…

opencv4.7.0编译opencv-contrib-4.7.0以及CUDA

0、引言 最近工作中需要用到使用CUDA加速后的opencv进行传统算法的开发,在编程之前,需要先解决环境编译和lib库问题,本文就是记录自己编译opencv-4.7.0的全过程。 1、CUDA下载和安装 可参考我之前的博客WIN10安装配置TensorRT详解中的前几…

我爱学QT-QT信号和槽

1.给控件改名字 为了分析代码方便,我们要给控件改名字。要通俗易懂。 2.信号和槽 信号:信号就是指控件发出的特定的信号。 比如按钮的信号 槽:槽就是槽函数的意思,我们可以把槽函数绑定在某一个控件的信号上。 3.怎么关联信号…

【无公网IP端口映射】远程访问本地jupyter notebook服务

文章目录 前言1. Python环境安装2. Jupyter 安装3. 启动Jupyter Notebook4. 远程访问4.1 安装配置cpolar内网穿透4.2 创建隧道映射本地端口 5. 固定公网地址 前言 Jupyter Notebook,它是一个交互式的数据科学和计算环境,支持多种编程语言,如…

学无止境·MySQL⑦(索引和视图)

索引和视图练习 索引练习1、建立一个utf8编码的数据库test12、建立商品表goods和栏目表category3、删除 goods 表中的 goods_desc 字段及货号字段,并增加 click_count 字段4、在 goods_name 列上加唯一性索引(用alter table方式)5、在 shop_price 列上加…

云之道知识付费V2小程序V3.1.1独立平台版安装使用教程

据播播资源了解,云之道知识付费小程序是一款专注于知识付费的小程序源码,为内容创业者、自媒体和教育培训机构提供全方位的互联网解决方案。 由播播资源小编全套安装云之道知识付费V2独立版系统,系统支持无限多开,相比上几版出现…

Tenable Nessus 10.5.3 (Unix, Linux, Windows) - #1 漏洞评估解决方案

Tenable Nessus 10.5.3 (Unix, Linux, Windows) - #1 漏洞评估解决方案 发布 Nessus 试用版自动化安装程序,支持 macOS Ventura、RHEL 9 和 Ubuntu 22.04 请访问原文链接:https://sysin.org/blog/nessus-10/,查看最新版。原创作品&#xff…

typescript helloword

创建文件夹 创建ch01文件夹 新建tsconfig.json {"compilerOptions": {"strict": true,"target": "ES5"} }“tsconfig.json”是TypeScript编译器默认使⽤的配置⽂件。此例中的配置⽂件启⽤了所有的严格类型检查编译选项,…