如何在SQL Server中实现Ungroup操作

news2024/11/19 0:32:29

概要

我们经常在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 cte1
	join 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 cte1
	join 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 cte2
	join 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 cte1
	join 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 cte2
	join 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 cte3
	join 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 -- 递归部分,即在查询中直接引用CTE
	Recursive terminatation condition -- 递归终止条件
)

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

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

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

with cte as (
	select * from products where total_count > 0
	union all
	select * from (
		select cte.id, cte.name, (cte.total_count -1) as total_count from cte
			join 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 products

create 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.coloradmin.cn/o/705165.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

【需求实现】Tensorflow2的曲线拟合(二):进度条简化

文章目录 导读普通的输出方式上下求索TensorBoard是个不错的切入点与Callback参数对应的Callback方法官方的内置Callback官方进度条简单的猜测与简单的验证拼图凑齐了! 导读 在训练模型的过程中往往会有日志一堆一堆的困扰。我并不想知道,因为最后我会在…

C# Excel表列名称

168 Excel表列名称 给你一个整数 columnNumber ,返回它在 Excel 表中相对应的列名称。 例如: A -> 1 B -> 2 C -> 3 … Z -> 26 AA -> 27 AB -> 28 … 示例 1: 输入:columnNumber 1 输出:“A”…

Unity与Android交互(4)——接入SDK

【前言】 unity接入Android SDK有两种方式,一种是把Unity的工程导出google project的形式进行接入,另一种是通过把Android的工程做成Plugins的形式进行接入。我们接入SDK基本都是将SDK作为插件的形式接入的。 对我们接入SDK的人来说,SDK也是…

一文了解PoseiSwap的质押系统

PoseiSwap 正在向订单簿 DEX 领域深度的布局,并有望成为订单簿 DEX 领域的早期开创者。

jmeter发送请求的request body乱码问题解决

JMeter的Put请求,响应结果中文出现乱码的解决方法 原文地址: http://www.taodudu.cc/news/show-808374.html?actiononClick

【云原生丶Kubernetes】从应用部署的发展看Kubernetes的前世今生

在了解Kubernetes之前,我们十分有必要先了解一下应用程序部署的发展历程,下面让我们一起来看看! 应用部署的发展历程 我们先来看看应用程序部署的3个阶段:从物理机部署到虚拟机部署,再到容器化部署,他们之…

Jenkins服务器连接JMeter分布式中的test-master

Jenkins想要连接test-master就要通过代理 将下载好的agent.jar传输到test-master机器上的/usr/local(实际上任何目录都可以)下 然后我们在/usr/local目录下输入: (这个是在Jenkins页面自己生成的命令) java -jar ag…

SQL频率低但笔试会遇到: 触发器、索引、外键约束

一. 前言 在SQL面笔试中,对于表的连接方式,过滤条件,窗口函数等肯定是考察的重中之重,但是有一些偶尔会出现,频率比较低但是至少几乎会遇见一两次的题目,就比如触发器,索引和外键约束&#xff0…

C++ 教程

C 教程 C 是一种高级语言,它是由 Bjarne Stroustrup 于 1979 年在贝尔实验室开始设计开发的。C 进一步扩充和完善了 C 语言,是一种面向对象的程序设计语言。C 可运行于多种平台上,如 Windows、MAC 操作系统以及 UNIX 的各种版本。 本教程通过…

Stanford点云公开数据集:S3DIS

S3DIS (Stanford Large-Scale 3D Indoor Spaces Dataset) 是斯坦福大学提供的大场景室内3D点云数据集,包含6个教学和办公Area,总共有695,878,620个带有色彩信息以及语义标签的3D点。 该数据集目前已经被包含在一个更大的Full 2D-3D-S Dataset当中&#x…

深入探讨Seata RPC模块的设计与实现

在Seata中,TM,RM与TC都需要进行跨进程的网络调用,通常来说就会需要RPC来支持远程调用,而Seata内部就有自身基于Netty的RPC实现,这里我们就来看下Seata是如何进行RPC设计与实现的 RPC整体设计 抽象基类AbstractNettyRemoting 该类是…

Dinky:问题总结

一、启动时指定flink版本,因为dinky本身也集成了部分flink ./auto.sh start 1.12 二、数据源管理新增mysql时的url jdbc:mysql://ip:3306/dinky?useUnicodetrue&characterEncodingutf8&useSSLfalse&autoReconnecttrue&failOverReadOnlyfalse 不要…

2、JAVA 分支结构 switch结构 for循环

1 分支结构 1.1 概述 顺序结构的程序虽然能解决计算、输出等问题 但不能做判断再选择。对于要先做判断再选择的问题就要使用分支结构 1.2 形式 1.3.1 练习:商品打折案例 创建包: cn.tedu.basic 创建类: TestDiscount.java 需求: 接收用户输入的原价。满1000打9折…

网工内推 | 运营商招网工,3年以上网安经验,CISP/CCIE认证优先

01 微算互联 招聘岗位:网络工程师 职责描述: 1、负责生产系统的网络管理、网络监控告警、网络设备数据资料备份/恢复容灾管理; 2、海外、tob 、私有云网络搭建及运维7 X 24小时值班; 3、负责业务系统工程网络层面规划、建设、升级…

Java之Javac、JIT、AOT之间的关系

Javac:javac 是java语言编程编译器。全称java compiler。但这时候还是不能直接执行的,因为机器只能读懂汇编,也就是二进制,因此还需要进一步把.class文件编译成二进制文件。 Java的执行过程 详细流程 结论:javac编译后…

使用Python调用aapt命令查看APK文件信息

以下演示内容在window的操作系统 1、下载 aapt 下载完成后注意配置环境变量!!! 地址:https://www.mediafire.com/file/e8ww8wbgcowbti4/aapt 2、代码实现 import os import re import subprocess#获取当前操作系统 current_os o…

S型平滑函数功能块(CODESYS ST完整源代码)

S型平滑函数在多段曲线控温上的应用。完整算法介绍请参看下面文章博客: 带平滑功能的斜坡函数(多段曲线控温纯S型曲线SCL源代码+完整算法分析)_RXXW_Dor的博客-CSDN博客PLC运动控制基础系列之梯形速度曲线,可以参看下面这篇博客:PLC运动控制基础系列之梯形速度曲线_RXXW_…

RTL8720CF烧录工具

一、环境准备 1、 解压烧录工具包 AmebaZII_PGTool_v1.2.39.zip 2、 日志串口接串口调试助手 3、 模组A0脚接高电平 二、烧录 1、模组重新上电,串口有Download Image over …… 输出,表示模组已进入烧录模式,如图: 2、打开上…

springboot+vue校园一卡通管理系统_q7e7o

近些年来,随着科技的飞速发展,互联网的普及逐渐延伸到各行各业中,给人们生活带来了十分的便利,校园一卡通利用计算机网络实现信息化管理,使整个校园一卡通管理的发展和服务水平有显著提升。 本文拟采用java技术和Sprin…

【算法题】动态规划中级阶段之买卖股票的最佳时机、三角形最小路径和

动态规划中级阶段 前言一、三角形最小路径和1.1、思路1.2、代码实现 二、买卖股票的最佳时机 II2.1、思路2.2、代码实现 总结 前言 动态规划(Dynamic Programming,简称 DP)是一种解决多阶段决策过程最优化问题的方法。它是一种将复杂问题分解…