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

MS SQL Server partition by 函数实战二 编排考场人员

 

目录

需求

输出效果

范例运行环境

表及视图样本设计

功能实现

生成考场数据

生成重复的SQL语句

封装为统计视图

编写存储过程实现统计

小结


需求

假设有若干已分配准考证号的考生,准考证号示例(01010001)共计8位,前4位为分类号,后4位为分类下的总排序号。现提供考场分配信息EXCEL文件(包括考场编号 、考场名称、考场容纳人数等),希望根据准考证号升序,将考生分配于对应的考场中,并生成对应的座位号(也即每一个考场的排序号),即分配原则为准考证号越小,考场号和座位号越靠前 。本文将继续介绍利用 partition by 、c# 来实现这一需求,主要实现如下功能:

(1)上传考场分布信息的EXCEL,导入生成考场信息数据。

(2)使用 C#  生成重复的SQL语句进行 union all 合并,生成考场座位信息。

(3)将准考证号信息左连接考场座位信息,生成考生分配明细表(包装为视图)。

(4)生成每个考场的准考证号以分类号(前4位)分组统计最小号和最大号范围。

输出效果

实现的考生准考证号分配表如下图:

如图,第1考场可容纳30人,座位号分配则从 1 到 30。分类为0101的准考证号在分配不开的情况下继续分配到 第2考场,座位号重新进行分配,以此类推。

另外,实现考场准考证号范围分类统计如下图:

如图,准考证号范围按前4位分组统计,输出最小号与最大号范围。 

范例运行环境

操作系统: Windows Server 2019 DataCenter

数据库:Microsoft SQL Server 2016

.netFramework 4.7.1

开发工具:VisualStudio 2019 C#

表及视图样本设计

考场表 [dlzp_kc] 设计如下:

序号字段名类型说明备注
1xm_ciduniqueidentifier所属项目ID比如某一考试项目
2kcbhnvarchar(6)考场编号按固定位补位排序
3kcmcnvarchar(50)考场名称
4kcrssmallint考场人数

含准考证号的考生视图 v_ypz 设计如下:

序号字段名类型说明备注
1xm_ciduniqueidentifier所属项目ID比如某一考试项目
2zkzhchar(8)准考证号固定8位

根据设计 v_ypz 数据集记录大于等于考场记录数,因此使用左连接以显示考场座位数不足的情况统计。

准考证号考场范围分布情况表 dlzp_kc_zkzhs 设计如下:

序号字段名类型说明备注
1xm_ciduniqueidentifier所属项目ID比如某一考试项目
2kcbhnvarchar(6)考场编号 
3kcmcnvarchar(50)考场名称冗余字段
4zkzhsnvarchar(500)准考证号范围转多行为一行数据

功能实现

生成考场数据

根据提供的EXCEL考场文件,导入到考场表(dlzp_kc)中,如何将EXCEL文件导入成数据集,可参考我的文章《C#实现Excel合并单元格数据导入数据集》,成功导入后,在查询分析器示例如下图:

生成重复的SQL语句

结合考场数据集,通过C# 循环遍历,得到我们想要的考场明细(输出容纳人数的记录数)数据集,代码如下:

//TextBox1为放置在 WebForm 上的文本框控件(多行设置)
//dt 为生成的考场数据集数据表(DataTable)TextBox1.Text = "select b.zkzh,a.* from(select ROW_NUMBER() over(order by zkzh) xh,zkzh  from v_ypz where xm_cid='" + _xm_cid + "' and zkzh is not null)  b left join (select ROW_NUMBER() over(order by kcbh) as xh,* from (";string dsql = "\r\nselect top {0} '{1}' kcbh,'{2}' kcmc,{3} kcrs,ROW_NUMBER() over(order by kcbh) zwh from v_ypz \r\n {4}";
for (int i = 0; i < dt.Rows.Count; i++)
{TextBox1.Text += string.Format(dsql, dt.Rows[i]["kcrs"].ToString(), dt.Rows[i]["kcbh"].ToString(), dt.Rows[i]["kcmc"].ToString(),dt.Rows[i]["kcrs"].ToString(), i == dt.Rows.Count - 1 ? "" : "union all");
}TextBox1.Text += ") a) a on a.xh=b.xh ";

该程序片断可辅助我们生成想要的SQL语句,以避免重复劳动,生成的最终结果如下:

select b.zkzh,a.* from 
(select xm,sfzh,ROW_NUMBER() over(order by zkzh) xh,zkzh from v_ypz where xm_cid='16286689-1097-4b9d-8c2a-06b4588ec289' and zkzh is not null)  b 
left join (
select ROW_NUMBER() over(order by kcbh) as xh,* from (
select top 30 '001' kcbh,'第1考场' kcmc,30 kcrs,ROW_NUMBER() over(order by kcbh) zwh from v_ypz union all
select top 30 '002' kcbh,'第2考场' kcmc,30 kcrs,ROW_NUMBER() over(order by kcbh) zwh  from v_ypz union all
select top 30 '003' kcbh,'第3考场' kcmc,30 kcrs,ROW_NUMBER() over(order by kcbh) zwh from v_ypz union all
select top 30 '004' kcbh,'第4考场' kcmc,30 kcrs,ROW_NUMBER() over(order by kcbh) zwh from v_ypz union all
select top 30 '005' kcbh,'第5考场' kcmc,30 kcrs,ROW_NUMBER() over(order by kcbh) zwh from v_ypz union all
select top 30 '006' kcbh,'第6考场' kcmc,30 kcrs,ROW_NUMBER() over(order by kcbh) zwh from v_ypz union all
select top 30 '007' kcbh,'第7考场' kcmc,30 kcrs,ROW_NUMBER() over(order by kcbh) zwh from v_ypz ) a) a on a.xh=b.xh

在主表 v_ypz 按准考证号升序生成总序号(xh) ROW_NUMBER() over(order by zkzh) xh,考场明细视图按考场编号升序生成总序号 (xh)ROW_NUMBER() over(order by kcbh) as xh,其中每个考场的则按考场编号生成座位号(zwh)ROW_NUMBER() over(order by kcbh) zwh,最后我们通过左连接即可得到我们想要的分配明细情况结果。

封装为统计视图

将上述分配明细查询进一步进行统计准考证号范围,封装为视图 v_a,SQL 语句如下:

create view [dbo].[v_a] as 
select kcbh,kcmc,lzkzh,zkzh2,zkzh3 from (select *,left(zkzh,4) lzkzh,
min(right(zkzh,4)) over (partition by kcbh,left(zkzh,4) order by kcbh,left(zkzh,4)) zkzh2,
max(right(zkzh,4)) over (partition by kcbh,left(zkzh,4) order by kcbh,left(zkzh,4)) zkzh3 
from ( 
select b.sfzh,b.xm,b.zkzh,a.* from(select xm,sfzh,ROW_NUMBER() over(order by zkzh) xh,zkzh  from v_ypz where xm_cid='16286689-1097-4b9d-8c2a-06b4588ec289' and zkzh is not null)  b left join (
select ROW_NUMBER() over(order by kcbh) as xh,* from (
select top 30 '001' kcbh,'第1考场' kcmc,30 kcrs,ROW_NUMBER() over(order by kcbh) zwh from v_ypz union all
select top 30 '002' kcbh,'第2考场' kcmc,30 kcrs,ROW_NUMBER() over(order by kcbh) zwh from v_ypz union all
select top 30 '003' kcbh,'第3考场' kcmc,30 kcrs,ROW_NUMBER() over(order by kcbh) zwh from v_ypz union all
select top 30 '004' kcbh,'第4考场' kcmc,30 kcrs,ROW_NUMBER() over(order by kcbh) zwh from v_ypz union all
select top 30 '005' kcbh,'第5考场' kcmc,30 kcrs,ROW_NUMBER() over(order by kcbh) zwh from v_ypz union all
select top 30 '006' kcbh,'第6考场' kcmc,30 kcrs,ROW_NUMBER() over(order by kcbh) zwh from v_ypz union all
select top 30 '007' kcbh,'第7考场' kcmc,30 kcrs,ROW_NUMBER() over(order by kcbh) zwh from v_ypz ) a) a on a.xh=b.xh   ) a   ) a  group by kcbh,kcmc,lzkzh,zkzh2,zkzh3
GO

其中我们通过 partition by 函数 按考场编号 及 左截取准考证号前4位(分类号)进行分区计算右截取准考证号的后4位,取最小号和最大号,如(zkzh2 为最小序号):

min(right(zkzh,4)) over (partition by kcbh,left(zkzh,4) order by kcbh,left(zkzh,4)) zkzh2

(zkzh3 为最大序号):

max(right(zkzh,4)) over (partition by kcbh,left(zkzh,4) order by kcbh,left(zkzh,4)) zkzh3

运行结果示例如下:

如图我们可以看到 lzkzh 为左截取的4位准考证分类号,zkzh2为最小号,zkzh3为最大号(本考场内),像第6考场,有两个分类范围,为了便于更直观的显示数据,将其显示为一行,我们可以编写存储过程来实现这一需求。 

编写存储过程实现统计

存储过程示例代码如下:

CREATE PROCEDURE [dbo].[kc_zkzhs] @xm_cid uniqueidentifier
AS
BEGINdelete dlzp_kc_zkzhs where xm_cid=@xm_cid insert into dlzp_kc_zkzhs(xm_cid,kcbh,kcmc,zkzhs) select @xm_cid,kcbh,kcmc,'' zkzhs from  dlzp_kc where xm_cid=@xm_cid declare @kcbh nvarchar(50)declare @lzkzh nvarchar(4)declare @zkzh2 nvarchar(4)declare @zkzh3 nvarchar(4)DECLARE _cursor CURSOR FOR  SELECT  kcbh,lzkzh,zkzh2,zkzh3 from v_a order by kcbh,lzkzh,zkzh2,zkzh3OPEN _cursor;  FETCH NEXT FROM _cursor  INTO @kcbh,@lzkzh,@zkzh2,@zkzh3  WHILE @@FETCH_STATUS = 0  BEGIN  update dlzp_kc_zkzhs set zkzhs=zkzhs+@lzkzh+@zkzh2+' - '+@lzkzh+@zkzh3+char(13)+char(10) where xm_cid=@xm_cid  and kcbh=@kcbhFETCH NEXT FROM _cursor  INTO @kcbh,@lzkzh,@zkzh2,@zkzh3   END  CLOSE _cursor;  DEALLOCATE _cursor;select a.kcbh 考场编号,a.kcmc 考场名称,b.kcrs 容纳人数,a.zkzhs 准考证范围  from dlzp_kc_zkzhs a,dlzp_kc b where a.xm_cid=@xm_cid  and a.xm_cid=b.xm_cid and a.kcbh=b.kcbhorder by a.kcbh
end

运行该存储过程可以将多行统计数据合并为单行进行显示,显示结果如下效果:

 

 

小结

1、我们的实际操作中有一百多个考场,为避免冗长的代码,示例代码片断并不完整,在这里仅为方便参考。

2、将多行转单行统计可以有很多种方法(比如STUFF函数),本文在这里编写的是存储过程,是一种比较兼容的写法,性能也还不错,否则使用 STUFF 大数据运算(视图)的时候,效果并不理想。更多方法可参考我的文章 《MS SQL Server STUFF 函数实战 统计记录行转为列显示》

3、更多 partition by 的聚合统计方法可参考我的文章 《MS SQL Server partition by 函数实战 统计与输出》

至此 partition by 的实例应用我们就介绍到这里,具体使用中我们还需要灵活掌握。感谢您的阅读,希望本文能够对您有所帮助。

相关文章:

  • 北京网站建设多少钱?
  • 辽宁网页制作哪家好_网站建设
  • 高端品牌网站建设_汉中网站制作
  • 提升录制效率,这些录屏软件快捷键你不可不知
  • 【C++ 面试 - 面向对象】每日 3 题(十)
  • 加速边缘智能技术落地!移远通信推出全功能ARM主板QSM560DR、QSM668SR系列
  • Midjourney推出网页版编辑器应对Ideogram 2.0冲击
  • 【ACL2024】基于长尾检索知识增强的大语言模型
  • nginxlvshaproxy负载均衡的区别
  • android 实战开发之Java 中生成从 1 到 3 的随机数
  • shell脚本(1)--一键启动zookeeper
  • 第三章 PyTorch的使用
  • git如何将多个提交合并为一个提交
  • 数学建模之数据分析【八】:数据预处理之数据格式化
  • 【傅里叶分析】复数基础知识
  • 搭建NFS服务器
  • 《黑神话悟空》:你绝对想知道的秘密
  • 编程达人Windows核心编程 第18章 演示如何使用堆
  • 345-反转字符串中的元音字母
  • 4. 路由到控制器 - Laravel从零开始教程
  • CAP 一致性协议及应用解析
  • create-react-app做的留言板
  • flask接收请求并推入栈
  • HTML中设置input等文本框为不可操作
  • java中的hashCode
  • k个最大的数及变种小结
  • Spring Boot快速入门(一):Hello Spring Boot
  • SwizzleMethod 黑魔法
  • 从零开始的无人驾驶 1
  • 浅谈Kotlin实战篇之自定义View图片圆角简单应用(一)
  • 数据仓库的几种建模方法
  • 思维导图—你不知道的JavaScript中卷
  • 微信小程序--------语音识别(前端自己也能玩)
  • 【运维趟坑回忆录】vpc迁移 - 吃螃蟹之路
  • Play Store发现SimBad恶意软件,1.5亿Android用户成受害者 ...
  • Semaphore
  • ​Python 3 新特性:类型注解
  • # 飞书APP集成平台-数字化落地
  • #《AI中文版》V3 第 1 章 概述
  • #include到底该写在哪
  • (42)STM32——LCD显示屏实验笔记
  • (动态规划)5. 最长回文子串 java解决
  • (二)基于wpr_simulation 的Ros机器人运动控制,gazebo仿真
  • (机器学习的矩阵)(向量、矩阵与多元线性回归)
  • (四)js前端开发中设计模式之工厂方法模式
  • (转)如何上传第三方jar包至Maven私服让maven项目可以使用第三方jar包
  • (转载)PyTorch代码规范最佳实践和样式指南
  • .[hudsonL@cock.li].mkp勒索病毒数据怎么处理|数据解密恢复
  • .mysql secret在哪_MYSQL基本操作(上)
  • .NET CORE 2.0发布后没有 VIEWS视图页面文件
  • .net 托管代码与非托管代码
  • .net反编译的九款神器
  • .NET学习全景图
  • /使用匿名内部类来复写Handler当中的handlerMessage()方法
  • [ C++ ] STL_list 使用及其模拟实现
  • [ 云计算 | AWS ] AI 编程助手新势力 Amazon CodeWhisperer:优势功能及实用技巧
  • [Android]使用Retrofit进行网络请求
  • [BT]小迪安全2023学习笔记(第15天:PHP开发-登录验证)