SQL笛卡尔积查询的典型应用
SQL笛卡尔积查询的典型应用
作者:AntoniotheFuture
关键词:SQL,笛卡尔积
开发平台:不限
开发语言:SQL
简介: 介绍一个利用SQL笛卡尔积查询来简化代码的典型应用
我的日常工作中经常用到SQL,但没用过笛卡尔积查询,以前一直以为他只会出现在逻辑出错的时候,而且通常意味着大量的资源开销,不过今天有幸能够使用一次,而且发现他能简化代码,分享给大家:
现在有一张员工信息表,记录着从创办公司到现在所有员工的信息:
人员代码 | 入职日期 | 离职日期 |
000001 | 2000-01-01 | |
000002 | 2002-05-15 | 2008-04-09 |
000003 | 2005-09-10 | |
000004 | 2005-10-01 | 2014-03-15 |
.... | .... | ... |
可能这时候就有DBA吐槽了,这个表不能这样设计,而是应该设计成任职记录表,每个员工多条记录,是我我也做成任职记录表,但是我们公司就是这样的
有一天老板心血来潮,他想看看我们公司的人力发展历史,就是统计公司自创办以来,每个月的在职人数,而且有个算法:当月入职或离职的算0.5个人,同月入职离职的不算在职。
以往我的思路是,将每个月的字段列出,然后分别判断该人员在当月是否在职,如果在职就为1,其他情况是0.5或者0,然后所有字段分别求和:
(case when to_date(入职日期,'yyyymm') < '200001' and to_date(离职日期,'yyyymm') >'200001' then1
when to_date(入职日期,'yyyymm') < '200001' and to_date(离职日期,'yyyymm') ='200001' then
0.5
when to_date(入职日期,'yyyymm') < '200001' and to_date(离职日期,'yyyymm') <'200001' then
0
when to_date(入职日期,'yyyymm') < '200001' and 离职日期 is null then
1
when to_date(入职日期,'yyyymm') = '200001' and to_date(离职日期,'yyyymm') >'200001' then
0.5
when to_date(入职日期,'yyyymm') = '200001' and to_date(离职日期,'yyyymm') ='200001' then
0
when to_date(入职日期,'yyyymm') = '200001' and 离职日期 is null then
0.5
when to_date(入职日期,'yyyymm') > '200001' then
0
else
0
end) as 200001在职人力
(case when to_date(入职日期,'yyyymm') < '200002' and to_date(离职日期,'yyyymm') >'200002' then1
when to_date(入职日期,'yyyymm') < '200002' and to_date(离职日期,'yyyymm') ='200002' then
0.5
when to_date(入职日期,'yyyymm') < '200002' and to_date(离职日期,'yyyymm') <'200002' then
0
when to_date(入职日期,'yyyymm') < '200002' and 离职日期 is null then
1
when to_date(入职日期,'yyyymm') = '200002' and to_date(离职日期,'yyyymm') >'200002' then
0.5
when to_date(入职日期,'yyyymm') = '200002' and to_date(离职日期,'yyyymm') ='200002' then
0
when to_date(入职日期,'yyyymm') = '200002' and 离职日期 is null then
0.5
when to_date(入职日期,'yyyymm') > '200002' then
0
else
0
end) as 200002在职人力
。。。。。
如果只求一两个月月到还好,但是现在要求所有月份,每年12个月12个字段,10年120个,代码虽然是规则的,但是也太长了,这么多字段,结果能不能输出还不一定呢。
于是我就想有没有优化的方案,灵光一闪,决定用笛卡尔积试试。
我们首先准备这样一张把所有月份列出来的表(可以从别的表group by而来):
月份 |
200001 |
200002 |
200003 |
..... |
然后直接和员工信息表做笛卡尔积,结果集是这样的:
select * from 员工信息,月份表
人员代码 | 入职日期 | 离职日期 | 月份 |
000001 | 2000-01-01 | 200001 | |
000001 | 2000-01-01 | 200002 | |
000001 | 2000-01-01 | 200003 | |
000001 | 2000-01-01 | 200004 | |
000001 | 2000-01-01 | 200005 | |
000001 | 2000-01-01 | 200006 | |
.... | ... | ... | ... |
就相当于列出了每个人员在每个月的情况,这个时候我们只需要做一个字段,根据入职日期,离职日期和月份计算该人员在该月份是否在职即可:
(case when to_date(入职日期,'yyyymm') < 月份 and to_date(离职日期,'yyyymm') >月份 then1
when to_date(入职日期,'yyyymm') < 月份 and to_date(离职日期,'yyyymm') =月份 then
0.5
when to_date(入职日期,'yyyymm') < 月份 and to_date(离职日期,'yyyymm') <月份 then
0
when to_date(入职日期,'yyyymm') < 月份 and 离职日期 is null then
1
when to_date(入职日期,'yyyymm') = 月份 and to_date(离职日期,'yyyymm') >月份 then
0.5
when to_date(入职日期,'yyyymm') = 月份 and to_date(离职日期,'yyyymm') =月份 then
0
when to_date(入职日期,'yyyymm') = 月份 and 离职日期 is null then
0.5
when to_date(入职日期,'yyyymm') > 月份 then
0
else
0
end) as 当月在职人力
得到的结果集是这样的:
人员代码 | 入职日期 | 离职日期 | 月份 |
当月在职人力 |
000001 | 2000-01-01 | 200001 | 0.5 | |
000001 | 2000-01-01 | 200002 | 1 | |
000001 | 2000-01-01 | 200003 | 1 | |
000001 | 2000-01-01 | 200004 | 1 | |
000001 | 2000-01-01 | 200005 | 1 | |
000001 | 2000-01-01 | 200006 | 1 | |
... | .. | ... | ... | .. |
然后就可以用月份group by 起来啦:
完整的伪代码如下,根据环境和不同的需求自行修改~
Select 月份,sum(case when to_date(入职日期,'yyyymm') < 月份 and to_date(离职日期,'yyyymm') >月份 then1when to_date(入职日期,'yyyymm') < 月份 and to_date(离职日期,'yyyymm') =月份 then 0.5when to_date(入职日期,'yyyymm') < 月份 and to_date(离职日期,'yyyymm') <月份 then 0when to_date(入职日期,'yyyymm') < 月份 and 离职日期 is null then 1when to_date(入职日期,'yyyymm') = 月份 and to_date(离职日期,'yyyymm') >月份 then0.5when to_date(入职日期,'yyyymm') = 月份 and to_date(离职日期,'yyyymm') =月份 then0when to_date(入职日期,'yyyymm') = 月份 and 离职日期 is null then0.5when to_date(入职日期,'yyyymm') > 月份 then0else0end) as 当月在职人力
from 员工信息表,月份表
group by 月份
结果示例:
月份 | 当月在职人力 |
201001 | 350 |
201002 | 364 |
201003 | 360 |
201004 |
372 |
..... | .... |
SQL笛卡尔积查询的典型应用相关推荐
- SQL Server高级查询之子查询(子查询非典型应用)
1.子查询非典型应用概述 1.子查询通常位于where字句中,但其也可以在from子句中和select子句的查询列中使用. 2.在from子句中使用子查询 3.在select子句的查询列中使用子查询 ...
- MySQL补充部分-SQL逻辑查询语句执行顺序
一 SELECT语句关键字的定义顺序 SELECT DISTINCT <select_list> FROM <left_table> <join_type> JOI ...
- mysql五补充部分:SQL逻辑查询语句执行顺序
mysql五补充部分:SQL逻辑查询语句执行顺序一 SELECT语句关键字的定义顺序 二 SELECT语句关键字的执行顺序 三 准备表和数据 四 准备SQL逻辑查询测试语句 五 执行顺序分析 一 SE ...
- QueryBuilder : 打造优雅的Linq To SQL动态查询
首先我们来看看日常比较典型的一种查询Form 这个场景很简单:就是根据客户名.订单日期.负责人来作筛选条件,然后找出符合要求的订单. 在那遥远的时代,可能避免不了要写这样的简单接口: public i ...
- sql查询初学者指南_面向初学者SQL Server查询执行计划–非聚集索引运算符
sql查询初学者指南 Now that we understand what Clustered Index Scan and Clustered Index Seek are, how they o ...
- MySQL学习记录 (二) ----- SQL数据查询语句(DQL)
相关文章: <MySQL学习记录 (一) ----- 有关数据库的基本概念和MySQL常用命令> <MySQL学习记录 (二) ----- SQL数据查询语句(DQL)> &l ...
- SQL Server 查询处理中的各个阶段
SQL Server 查询处理中的各个阶段 SQL 不同于与其他编程语言的最明显特征是处理代码的顺序.在大数编程语言中,代码按编码顺序被处理,但是在SQL语言中,第一个被处理的子句是FROM子句,尽管 ...
- Hive SQL数据查询基础
教材第四章Hive SQL数据查询基础实验 提示:如果感觉sogou.500w.utf8文件太大,执行hive命令太耗时间,可以执行以下命令,截取前1万行数据,生成一个新的数据文件sogou.1w.u ...
- 阿里云天池龙珠计划SQL入门与实践 | Task02 SQL基础查询与排序
本文为阿里云天池学习<SQL入门与实践>第二讲学习笔记,同时该讲内容基于<SQL基础教程>第二章(查询基础)及第三章(聚合与排序). SQL基础查询与排序 一.SELECT语句 ...
- mysql基础10(SQL逻辑查询语句执行顺序)
SQL语句定义顺序 SELECT DISTINCT <select_list> FROM <left_table> <join_type> JOIN <rig ...
最新文章
- [USACO07JAN]平衡的阵容Balanced Lineup BZOJ 1699
- 常考数据结构与算法:用两个栈实现队列
- 1,1 一维运动公式
- 图片动画横条广告带上下滚动
- java里正数和负数_Java程序检查数字是正数还是负数
- HibernateAnnotation入门实例
- Master PDF Editor for Mac(PDF文档编辑软件)
- 认知无线电网络的简单介绍
- bxp3.3与其他版本的区别(转)
- 华为网络配置(路由配置)
- Python语言(实践)练习题——函数及代码复用
- 家居风水大全[ZT:http://sssyyyccc.blog.hexun.com/2641355_d.html]
- Android 9.0系统源码_SystemUI(四)通知图标控制器
- JRE和JDK和JVM
- 算法岗面经总结(映客 )
- wordpress安装和使用图文教程(新手指南)
- 电子电路分析与设计:数字电子技术_电子电路分析浅谈
- 新媒体运营,微博运营简介与操作
- 关于Http协议,一片就够了
- 君正T41 AI 视频处理器
热门文章
- 麒麟系统更改SSH端口号
- centos服务器修改密码,linux centos默认的密码
- linux nginx rtmp 直播,linux下利用nginx搭建rtmp直播服务
- 2020年计算机保研经验总结
- virtualbox 安装centeros
- 【裴礼文数学分析】例1.2.4
- 解决win10系统安装ch341驱动程序显示“预安装成功”的一个方法
- 面试求职:数据库常见面试题(数据库优化思路)
- MATLAB数字水印处理技术的实现
- mysql软件可行性分析报告_软件工程作业 图书馆管理系统可行性分析报告