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笛卡尔积查询的典型应用相关推荐

  1. SQL Server高级查询之子查询(子查询非典型应用)

    1.子查询非典型应用概述 1.子查询通常位于where字句中,但其也可以在from子句中和select子句的查询列中使用. 2.在from子句中使用子查询 3.在select子句的查询列中使用子查询 ...

  2. MySQL补充部分-SQL逻辑查询语句执行顺序

    一 SELECT语句关键字的定义顺序 SELECT DISTINCT <select_list> FROM <left_table> <join_type> JOI ...

  3. mysql五补充部分:SQL逻辑查询语句执行顺序

    mysql五补充部分:SQL逻辑查询语句执行顺序一 SELECT语句关键字的定义顺序 二 SELECT语句关键字的执行顺序 三 准备表和数据 四 准备SQL逻辑查询测试语句 五 执行顺序分析 一 SE ...

  4. QueryBuilder : 打造优雅的Linq To SQL动态查询

    首先我们来看看日常比较典型的一种查询Form 这个场景很简单:就是根据客户名.订单日期.负责人来作筛选条件,然后找出符合要求的订单. 在那遥远的时代,可能避免不了要写这样的简单接口: public i ...

  5. sql查询初学者指南_面向初学者SQL Server查询执行计划–非聚集索引运算符

    sql查询初学者指南 Now that we understand what Clustered Index Scan and Clustered Index Seek are, how they o ...

  6. MySQL学习记录 (二) ----- SQL数据查询语句(DQL)

    相关文章: <MySQL学习记录 (一) ----- 有关数据库的基本概念和MySQL常用命令> <MySQL学习记录 (二) ----- SQL数据查询语句(DQL)> &l ...

  7. SQL Server 查询处理中的各个阶段

    SQL Server 查询处理中的各个阶段 SQL 不同于与其他编程语言的最明显特征是处理代码的顺序.在大数编程语言中,代码按编码顺序被处理,但是在SQL语言中,第一个被处理的子句是FROM子句,尽管 ...

  8. Hive SQL数据查询基础

    教材第四章Hive SQL数据查询基础实验 提示:如果感觉sogou.500w.utf8文件太大,执行hive命令太耗时间,可以执行以下命令,截取前1万行数据,生成一个新的数据文件sogou.1w.u ...

  9. 阿里云天池龙珠计划SQL入门与实践 | Task02 SQL基础查询与排序

    本文为阿里云天池学习<SQL入门与实践>第二讲学习笔记,同时该讲内容基于<SQL基础教程>第二章(查询基础)及第三章(聚合与排序). SQL基础查询与排序 一.SELECT语句 ...

  10. mysql基础10(SQL逻辑查询语句执行顺序)

    SQL语句定义顺序 SELECT DISTINCT <select_list> FROM <left_table> <join_type> JOIN <rig ...

最新文章

  1. [USACO07JAN]平衡的阵容Balanced Lineup BZOJ 1699
  2. 常考数据结构与算法:用两个栈实现队列
  3. 1,1 一维运动公式
  4. 图片动画横条广告带上下滚动
  5. java里正数和负数_Java程序检查数字是正数还是负数
  6. HibernateAnnotation入门实例
  7. Master PDF Editor for Mac(PDF文档编辑软件)
  8. 认知无线电网络的简单介绍
  9. bxp3.3与其他版本的区别(转)
  10. 华为网络配置(路由配置)
  11. Python语言(实践)练习题——函数及代码复用
  12. 家居风水大全[ZT:http://sssyyyccc.blog.hexun.com/2641355_d.html]
  13. Android 9.0系统源码_SystemUI(四)通知图标控制器
  14. JRE和JDK和JVM
  15. 算法岗面经总结(映客 )
  16. wordpress安装和使用图文教程(新手指南)
  17. 电子电路分析与设计:数字电子技术_电子电路分析浅谈
  18. 新媒体运营,微博运营简介与操作
  19. 关于Http协议,一片就够了
  20. 君正T41 AI 视频处理器

热门文章

  1. 麒麟系统更改SSH端口号
  2. centos服务器修改密码,linux centos默认的密码
  3. linux nginx rtmp 直播,linux下利用nginx搭建rtmp直播服务
  4. 2020年计算机保研经验总结
  5. virtualbox 安装centeros
  6. 【裴礼文数学分析】例1.2.4
  7. 解决win10系统安装ch341驱动程序显示“预安装成功”的一个方法
  8. 面试求职:数据库常见面试题(数据库优化思路)
  9. MATLAB数字水印处理技术的实现
  10. mysql软件可行性分析报告_软件工程作业 图书馆管理系统可行性分析报告