row_number 和 cte 使用实例:分组轮流排班

row_number 和 cte 使用实例:分组轮流排班

  • 分组轮流排班
    • 需求小分析
      • 使用 cte 模拟临时数据
      • 使用 row_number 分组编号
      • 使用聚合函数得到各组最大值
      • 使用日期差函数计算轮班天数
      • 使用求余运算完成排班
      • 使用列转行完成当日排班表
  • 小结

分组轮流排班

问题出自问答区某个小伙伴的问题,原地址:https://ask.csdn.net/questions/7910424

小伙伴的问题描述的稍微有些不那么清晰,老顾重新描述一遍

有某工厂,多个车间,每个车间中工人数量不同,每天需要所有车间都派出一个人进行值班,在该车间所有人都进行完值班前,不重复安排值班。

在实现这个问题之前,还是按照老顾的习惯,先进行一下分析,我们需要哪些步骤,如何实施我们的需求?

需求小分析

1、我们需要对每个车间的人员进行一个编号,按照编号顺序值班
2、我们需要知道从哪一天开始值班,这一天,所有值班人员的编号都是1,即第一个人
3、我们需要知道每个车间有多少人,可以计算该车间多少天轮流一轮
4、我们需要知道从开始值班那一天到指定日期的时间差
5、在非必要情况下,没有人员变动,比如新入职或离职或请假等问题

那么,分析结束后,我们的实现逻辑也就出来了,第一步,给所有人员按车间分组进行编号,一个大家都很熟悉的开窗函数 row_number 就此闪亮登场。

使用 cte 模拟临时数据

嗯,先用 cte 模拟一些数据出来,就不建立临时表了

with t as ( -- 原始数据
    select 1 as id,'aaa' name,'A' job
    union all select 2,'aba','A'
    union all select 3,'xxz','A'
    union all select 4,'fee','B'
    union all select 5,'3fee','B'
    union all select 6,'f5ee','B'
    union all select 7,'f4ee','B'
    union all select 8,'fe8e','B'
    union all select 9,'fe0e','B'
    union all select 16,'tte','Bc'
    union all select 17,'xtxt','Bc'
    union all select 18,'uyuy','Bc'
    union all select 19,'zzz','Bc'
)
select * from t

在这里插入图片描述

这里使用了 cte 表作为数据来源了,关于 cte 表的使用,大家可以自行百度一下,大部分数据库现在都是支持 cte 使用的。

不过,作为微软系软件的使用者,老顾推荐看 msdn 的原文:https://learn.microsoft.com/zh-cn/previous-versions/sql/sql-server-2008-r2/ms190766(v=sql.105)?redirectedfrom=MSDN,https://learn.microsoft.com/zh-cn/previous-versions/sql/sql-server-2008-r2/ms175972(v=sql.105),这里有简单的示例和完整的语法说明。

老顾使用 cte 不喜欢先定义字段名,因为这种用法是针对已有现成数据的情况下,不需要定义数据类型,而老顾做模拟数据,一般喜欢直接用第一行数据来定义字段名和数据类型。

使用 row_number 分组编号

在使用 cte 的时候,大部分数据库是支持连环使用多次调用的,否则也没法做 cte 递归查询了,当然递归不是这个需求的重点,老顾想说的是 cte 支持连续多次书写

with cte1 as (),cte2 as (),cte3 as ()

所以,我们接着上边的内容书写

with t as ( -- 原始数据
    select 1 as id,'aaa' name,'A' job
    union all select 2,'aba','A'
    union all select 3,'xxz','A'
    union all select 4,'fee','B'
    union all select 5,'3fee','B'
    union all select 6,'f5ee','B'
    union all select 7,'f4ee','B'
    union all select 8,'fe8e','B'
    union all select 9,'fe0e','B'
    union all select 16,'tte','Bc'
    union all select 17,'xtxt','Bc'
    union all select 18,'uyuy','Bc'
    union all select 19,'zzz','Bc'
),t1 as ( -- 按job划分每个人需要的值班序号
    select *,row_number() over(partition by job order by id) wid from t
)
select * from t1

在这里插入图片描述
可以看到,使用了 row_number 后,根据 partition 分组,每个相同的 job 的人员都有不同的编号了,需要注意的是,不管是 row_number 也好,rank也好,都是从数字1开始分配序号的,而不是大家编程时习惯的下标0开始的索引。

使用聚合函数得到各组最大值

再接着前边的 cte 指令续写,直接引用 t1 的数据,使用 max 聚合函数得到最大的序号,就是这个组内的人数了。

with t as ( -- 原始数据
    select 1 as id,'aaa' name,'A' job
    union all select 2,'aba','A'
    union all select 3,'xxz','A'
    union all select 4,'fee','B'
    union all select 5,'3fee','B'
    union all select 6,'f5ee','B'
    union all select 7,'f4ee','B'
    union all select 8,'fe8e','B'
    union all select 9,'fe0e','B'
    union all select 16,'tte','Bc'
    union all select 17,'xtxt','Bc'
    union all select 18,'uyuy','Bc'
    union all select 19,'zzz','Bc'
),t1 as ( -- 按job划分每个人需要的值班序号
    select *,row_number() over(partition by job order by id) wid from t
),t2 as ( -- 获得每个班有多少人进行轮班
    select job,max(wid) nums from t1 group by job
)
select * from t2

在这里插入图片描述

使用日期差函数计算轮班天数

假定我们从2023年1月1日起开始实施这个排班计划,那么我们就需要指定开始日期为 2023-1-1 了,然后使用时间差函数 datediff 来计算我们需要排版的天数。

select datediff(d,'2023-1-1',getdate()) -- 今天是2023年4月3日,所以日期差为92天

在这里插入图片描述
这里需要注意了,日期差的索引是从0开始的。。。。即2023-1-1是第 0 天!

使用求余运算完成排班

有了天数差之后,我们就可以和各组的人数进行求余,余 0 的为第一个人,余 1 的为第二个人,以此类推,所以最后的指令就出来了。

with t as ( -- 原始数据
    select 1 as id,'aaa' name,'A' job
    union all select 2,'aba','A'
    union all select 3,'xxz','A'
    union all select 4,'fee','B'
    union all select 5,'3fee','B'
    union all select 6,'f5ee','B'
    union all select 7,'f4ee','B'
    union all select 8,'fe8e','B'
    union all select 9,'fe0e','B'
    union all select 16,'tte','Bc'
    union all select 17,'xtxt','Bc'
    union all select 18,'uyuy','Bc'
    union all select 19,'zzz','Bc'
),t1 as ( -- 按job划分每个人需要的值班序号
    select *,row_number() over(partition by job order by id) wid from t
),t2 as ( -- 获得每个班有多少人进行轮班
    select job,max(wid) nums from t1 group by job
)
select *,datediff(d,'2023-1-1',getdate()) % nums 
from t1 a
left join t2 b on a.job=b.job
-- 获得自2023年1月1日开始排版后,今天需要排班的人员
where datediff(d,'2023-1-1',getdate()) % nums = wid - 1

在这里插入图片描述
这里使用了关联查询,将最大人数和排班组合起来了,然后根据日期求余结果筛选出符合的人员。嗯,刚才提醒过了 wid 是从1开始的,日期差求余是从 0 开始的,所以我们这里 wid - 1。

使用列转行完成当日排班表

最后的最后,就是如问答题主的要求一样了,使用列转行,只列当天每个车间需要值班的人员名单。pivot 是 mssql 特有的一个指令,非常实用哦。mysql 在进行行转列,列转行时就废了老劲了。

with t as ( -- 原始数据
    select 1 as id,'aaa' name,'A' job
    union all select 2,'aba','A'
    union all select 3,'xxz','A'
    union all select 4,'fee','B'
    union all select 5,'3fee','B'
    union all select 6,'f5ee','B'
    union all select 7,'f4ee','B'
    union all select 8,'fe8e','B'
    union all select 9,'fe0e','B'
    union all select 16,'tte','Bc'
    union all select 17,'xtxt','Bc'
    union all select 18,'uyuy','Bc'
    union all select 19,'zzz','Bc'
),t1 as ( -- 按job划分每个人需要的值班序号
    select *,row_number() over(partition by job order by id) wid from t
),t2 as ( -- 获得每个班有多少人进行轮班
    select job,max(wid) nums from t1 group by job
)
select * -- 最后按照班列出今天需要排班的人
from (
    select name,a.job 
    from t1 a
    left join t2 b on a.job=b.job
    -- 获得自2023年3月1日开始排版后,今天需要排班的人员
    where datediff(d,'2023-1-1',getdate()) % nums = wid - 1
) a
pivot(max(name) for job in (A,B,Bc)) p -- 这里需要把所有的班名都列出

在这里插入图片描述
最后的结果出来了,4月3日需要值班的分别是A车间的xxx,B车间的f5ee,Bc车间的tte。

列转行有一个需要注意的地方,那就是不要出现多余的字段,如果有多余字段且数据不重复的话,那么会分成多行,无法合并到一行上。

小结

这次我们使用了不少基础内容,灵活运用已经学会的内容,进行个性化组合,就可以完成从未设想过的功能了。cte,row_number,日期计算,列转行,这几项内容,大家如果想要深入学习,自行百度即可,虽然同质化比较严重,但好文章还是不少的。愿大家都能做一匹千里好马,驰骋万里。
在这里插入图片描述

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

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

相关文章

基于单片机的室内空气质量检测系统设计_kaic

目录 设计总说明 Instruction 1 绪论 1.1 设计背景及意义 1.2 国内外现状 1.3 设计内容及要求 2 室内空气质量标准及改善方式 2.1 室内空气质量标准参数 2.2 室内空气品质监测方法 2.3 改善空气品质方法 3.1 各模块电路的方案选择和讨论证明 3.1.1 单片机模块的选取和讨论 3.1.…

IOS - 某段子APP分析

抓包走起: 我这边习惯用vpn转发方式; 直接抓出来2.0协议了; 上trace url定位吧; frida-trace -UF -m "+[NSURL URLWithString:]"11891 ms 堆栈 from: 0x101b67038 /var/containers/Bundle/Application/72A10900-034F-400A-A822-6F5BB4FE6933/tieba.app/tie…

实现js程序在vscode控制台输出的方法(看完方便多了)

当我们想要写一段js代码时,我们可能会在vscode中新建一个html文件,然后再script标签下去编写js代码,完了之后我们想要看看js打印输出的效果,还会通过浏览器的 F12 去查看输出结果。好麻烦呀~ 如何解决呢? 我们可以在…

红黑树(算法导论版)

1 定义 (1)每个节点是红色或者黑色的。 (2)根节点是黑色的。 (3)所有叶子结点(NIL)都是黑色的。 (4)如果一个节点是红色,则它的两个子节点都…

nginx反向代理网页502、SSL_do_handshake()握手失败

配置反向代理后,开发反馈网页502,手里辣条吃完,自己试了一把,竟然不行 看看配置文件,没什么问题 之前一直这么写的不科学呀,换百度试试,百度可以,测试代理的域名直接访问也正常 日志…

聊聊MySQL主从延迟

文章目录 MySQL 的高可用是如何实现的呢?二、什么是主备延迟?三、主备延迟常见原因1、备库机器配置差2、备库干私活3、大事务四、主库不可用,主备切换有哪些策略?1、可靠优先2、可用优先实验一实验二3、结论MySQL 的高可用是如何实现的呢? 高可用性(high availability,缩…

SpringBoot整合XXL分布式任务调度(图文详细)

SpringBoot整合XXL分布式任务调度 1 简介 1.1 官网地址 官网地址: https://www.xuxueli.com/xxl-job/ 1.2 概述 XXL-JOB是一个分布式任务调度平台,其核心设计目标是开发迅速、学习简单、轻量级、易扩展。 1.3 功能特性 1、简单:支持通过Web页面对任…

ThreeJS-VR小岛(二十七)

素材: 链接: https://pan.baidu.com/s/1CXaRgxuIfKfzjDRJ8Gx1oQ 提取码: prg3 复制这段内容后打开百度网盘手机App,操作更方便哦 关键代码: let rgbeLoader new RGBELoader(); rgbeLoader.loadAsync("three/050.hdr").then((l…

Windows配置虚拟网络

系列精品文章目录 centos7配置静态网络常见问题归纳_centos7网络问题_张小鱼༒的博客-CSDN博客 python当中的第三方wxPython库的安装解答_pip install wx_张小鱼༒的博客-CSDN博客 jupyter notebook第八章pyecharts库的一些案例分析加相关函数的解析_jupyter安装pyecharts_张…

ASEMI代理HMC717ALP3E原装ADI(亚德诺)车规级HMC717ALP3E

编辑:ll ASEMI代理HMC717ALP3E原装ADI(亚德诺)车规级HMC717ALP3E 型号:HMC717ALP3E 品牌:ADI /亚德诺 封装:QFN-16 批号:2023 安装类型:表面贴装型 引脚数量:16 …

Kafka3.0.0版本——生产者同步发送消息 (API代码示例)

目录一、生产者同步发送消息&#xff08;API代码示例&#xff09;1.1、pom文件导入依赖1.2、API代码1.3、在 kafka集群服务器上开启 Kafka 消费者一、生产者同步发送消息&#xff08;API代码示例&#xff09; 1.1、pom文件导入依赖 依赖包 <dependency><groupId>o…

【SSM】Spring6(七.Spring IoC注解式开发)

文章目录1.声明Bean的注解2.Spring注解的使用2.1 添加aop的依赖2.2 在配置文件中添加context命名空间2.3 在配置文件中指定要扫描的包2.4 在Bean上使用注解2.5 细节3.选择实例化Bean3.1 方案一3.2 方案二4.负责注入的注解4.1 value4.2 Autowired Qualifier4.3 Resource5.全注解…

第四届国际工业信息安全应急大会完美落幕,赛宁网安载誉满满!

3月22-24日&#xff0c;为期2天半的第四届国际工业信息安全应急大会&#xff08;以下简称大会&#xff09;在北京市通州区圆满落幕。大会以“共话安全&#xff0c;共赢发展&#xff0c;共建开放协同新生态”为主题&#xff0c;共设交流论坛、应急大赛、产业推介会、线下展区、投…

linux命令整理版

目录 日志查看命令 tail命令 cat命令 vi(vim)命令 more命令 日志查看命令 tail命令 命令格式&#xff1a;tail &#xff3b;必要参数&#xff3d;&#xff3b;选择参数&#xff3d;&#xff3b;文件&#xff3d; -f 循环读取-v 显示详细的处理信息-c <数目>显示字…

FreeRTOS任务状态迁移图

野火书上的任务状态迁移图片说明看起来比较费劲所以特地做了这个图&#xff0c;各位在学习FreeRTOS的时候&#xff0c;做笔记也没那么费劲。 参考&#xff1a;《FreeRTOS内核实现与应用开发实战指南基于STM32》

[C++]C++基础知识概述

目录 C基础知识概述&#xff1a;&#xff1a; 1.什么是C 2.C发展史 3.C关键字 4.命名空间 5.C的输入输出 6.缺省参数 7.函数重载 8.引用 9.内联函数 10.auto关键字(C11) 11.基于范围的for循环(C11) 12.指针空值—nullptr(C11) C基础知识概述&#xff1…

子网掩码和CIDR

CIDR是什么 网络标识相同的计算机必须同属于同一个链路。例如&#xff0c;架构B类IP网络时&#xff0c;理论上一个链路内允许6万5千多台计算机连接。然而&#xff0c;在实际网络架构当中&#xff0c;一般不会有在同一个链路上连接6万5千多台计算机的情况。因此&#xff0c;这种…

vue实现油色谱大卫三角

效果图 直接上源码 <template> <div> <el-row> <el-col :span="17"> <canvas ref="canvas" style="margin-top: -8px" :width="height" :height="height" ></canvas> <…

【Python】PyCharm 快捷操作说明(Tip of the Day):Ctrl 键

目录 1. Ctrl ① 跳转到类、方法或变量的声明处 2. Ctrl 空格 ① 代码自动完成功能 ② 完成任何类的名称 ③ 基本代码完成功能 ④ 自动完成图片文件名 ⑤ 调用代码完成功能的特殊变体 ⑥ 查找命令行语法或可用函数 3. Ctrl B ① 导航到代码中某个地方使用的类、方…
最新文章