HIT工程师必修课《SQL实践》

2019-11-13  本文已影响0人  阿火_29b1

      今天很荣信,受董世新主任邀请来山东美丽的泰安市,感谢山东医信会给我这样一个机会与山东的医信同行们做分享交流!

一、我的工作感受

    因为今天是拓导课,我首先谈一下工作感受。我是从2009年进入HIT行业,至今也有10年了,人们常说“台上一分钟,台下十年功”,这句话告诉我们医信人如果没有经历十年功夫磨练,成为不了真正的行业专家。根据《刻意练习》这本书里面所描述的,一个普通人要想从菜鸟成长为行业技术专家,大概需要经过一万小时刻意练习,我计算一下10000小时是多少年, 10000小时/每天2小时/365天 = 13.69年,为什么是计算每天2个小时,很多时候我们的工作只是重复过去(为什么许多保安干了一辈子也没有变成专家,因为他们只是简单重复过去),如果我们每天真的能花2小时,真正去学习一门新知识、改进一下自己的工作方式、总结一下工作方法,那是一件了不得的事。这样日积月累,量变就会产生质的变化,就会变成行业专家。按照这个标准,我今天不用谦虚了,也算半个专家。

    改进一下自己的工作方式举例:比如我们his系统里面经常出错处理方法,进行半自化处理,所以我开发了“智能维护”功能模块,提高工作效率;

智能维护

对于一些常用的统计,做成报表给到临床科室,我们科室一共做了150张报表;

信息科制作报表

      对于上面我的这2个问题,其实很多人都想到了,很多时候为什么没有去做,我觉得原因有4个。第一个原因:因为懒,这是人的天性,原来有一种解决方法,我们不会去寻找另外的解决方法;第二个原因:因为没有能力去做,我不会用pb、delphi,也不会写存储过程,这个时候需要我们走出舒适区,进一步提升一下自己的技术能力;第三个原因:我太忙,没时间去做,那要看你忙什么,你是在开发软件、上线项目?还是修打印机、重装系统等。效率的本质是用最少的时间做最多的事,且尽量避免重复劳动及无技术含量的工作,怎样减少工作就是一门技术。所以我们不要用战术上的勤奋掩盖战略上的懒惰。第四个原因:觉得我“亏”了,为什么他不做,叫我做,我做了这件事情,又没有回报,面对这种问题我有时候会对自己说是技术能力重要还是“亏”重要。技术水平在原地踏步,想干一点事,发现自己已经变成中年老油条,技术落伍干不了,最后碌碌无为,在这里我只想提一个问题,这是你真的想要的人生吗?这个问题大家可以多问自己几遍,我们每个人需要对自己人生负责,我们怎么看待我们自己,就决定我们怎么去做!

    学习一门新知识举例:比如我最近在学习python语言半年,我发现python十分简单易用,将来如果开发大数据应用,我要与时俱进。

      总结一下工作方法举例:比如维护软件、维护硬件、开发软件的经验总结。今天我讲的这个课其实就是在整理过去10年写sql语句经验的总结;

    我们学习HIT知识路径,首先获取(别人告诉我的、向别人请教来的、自己看书来、看教程视频的等等)、然后去实践(学了pb以后先去写个小程序)得到经验、再总结(把重点再捋一下,相当于第二次学习),在你脑子里面就形成一个知识地图(知识闭环)。

二、为什么讲sql

      为什么今天我今天要说sql,这个不是一个医信工程师基本功吗?是的,没有错,虽然sql语句是基本功,但是要精通就很难,精通只有极少数人掌握了。就好像《算法与数据结构》这种基本功,我和在场各位只要大学上的计算机专业基本都学过,但是未必拍胸脯说自己掌握的很好。sql语句发明至今,一直很稳定,sql掌握的好不好,对于我们医信工程师来说是顺利的开展工作是一个关键。将下来我要分享我这里10年经验总结。

      在这里我分享最近遇到的一个坑,在deepin下面安装 mysql,花了2星期才弄好。我们眼里所谓的“高手”,只不过是面对一个个困难解决不了的时候,第二天早上醒来的时候,对自己说try again(再试一次)。

    我建议大家学习一门新知识的时候,使用虚拟机环境来做,因为虚拟机有一个快照功能,如果测试的过程发现了问题,直接回滚正常状态,还样十分方便。

三、sql重要几个概念

1、集合

SQL 以关系代数为基础发展出来的一门语言,关系代数主要是“集合”,也是sql最核心的概念

sql语句形式:select .... from ....

集合在sql当中的表现形式:每一个select语句都是一个集合,写在from后面的每个表、子查询、视图可以算作一个集合

第1种情况 第二种情况 第三种情况

2、笛卡尔积

select * from table1,table2,table1存在a列m行,table12存在b列n行,最后形成的集合是(a+b)列,(m*n)行记录

“笛卡尔积”是sql语句最重要的理论基础,任何sql语句其实到最后都是回归一个“笛卡尔积”里面捞数据,就像计算机最后回归到0和1执行。我为什么这样说,一个最简单的sql语句就是一个 “笛卡尔积“,后面使用where来筛选数据。为什么我们有时候要使用select distinct去重,当你的sql语句复杂以后,即可你已经使用where条件保证每个表之间都是内连接(一对一),但是有时候也很难保证最后集合结果是你期望的形式展现出来(可能存在相同的记录)。

3、集合之间的关系

集合之间的关系 一对一、一对多(最频繁)、多对多(几乎不用),在数据库表中通常用FOREIGN KEY表示一对多的关系 。

一对多的应用场景:

a)、批量插入某工号到每个病区的权限;

insert into 操作员表

select  * from 员工表,病区表 where 员工表.员工号=‘111’

b)、打印贴瓶单,根据次数生成多条记录

select * from 医嘱 ,次数表 where 医嘱.次数代码 = 次数表.代码

c)、一个检验组合对应多个检验项目,比如:肝功五项,肾功六项

d)、一个医保编码对应药监码,比如:X-L01XE-P135-E001(哌柏西利胶囊)对应86978724001194,86978724001200

4、null和空字串之间的区别

  null指的是理论意义上的空和绝对的空,空字串、空数组、空对象指有含义的空。

  所以null一般使用身份运算符 is,以示区分,is null或者is not null。像python是用is判断,但是java,js中用==来判断,有些编程语言对这个问题并没有严格区分。

四、写sql语句需要解决的几个问题

1、集合之间连接

2个集合之间需要连接,我们需要思考2个问题,关联字段和它们的关系(一对一、一对多、多对多)

当sql语句复杂以后了,很可能出现记录重复的现象,与你的预期不符,我们可以distinct去重。

内连接比较简单,不再介绍。

左连接LEFT JOIN左表全记录,右表符合条件

select * from t_A a left  join t_B b on a.id = b.id;

Select * from t_A a,t_B b where a.id=b.id(+);

用(+)来实现, 这个+号可以这样来理解: + 表示补充,即哪个表有加号,这个表就是匹配表。如果加号写在右表,左表就是全部显示,所以是左连接。

右连接RIGHT JOIN右表全记录,左表符合条件,操作与左连接相反

2、对集合数据字段的转换

oracle环境下举例:

decode(t1.xb, '1', '男', '2', '女', '不详') sex, 性别转换

decode(t.cyqk, '1','治愈','2','好转','3','未愈','4','死亡','5','24h内死亡','6','未治','7','其他') 出院情况转换

nvl(t.cyrq,sysdate) cyrq为null转换为当前日期,否则就是cyrq原来的值

substr(a.fpatno, 6) hisid, --门诊流水号

to_char(floor(b.pat_age)) || b.age_unit patient_age, --年龄

mysql环境下举例:

datediff(NOW(), t1.create_rq) + 1 计算两个日期相差天数

IF (t.`status` = '已完成', 1, 0) 

3、where条件集合数据

mysql环境下举例:

WHERE  t.create_rq >= '2018-08-01‘  AND t.create_rq < '2018-09-01'  限定时间

where  a1.`status` <> '已完成'  AND a1.create_deptid LIKE 'V%'

                                        where条件优先级别

4、集合进行数据聚合(类似于excel分类汇总)

group by 用法的概述

“Group By” 就是根据“By”指定的规则对数据进行分组,所谓的分组就是将一个“数据集”划分成若干个“小区域”,然后针对若干个“小区域”进行数据处理。

聚合函数的用法

                    Max              求最大

                    Min                求最小

                    Sum              求总和

                    Avg                求平均

                    Count            计算总行数

5、集合之间的计算

合并查询结果

合并查询结果是将多个SELECT语句的查询结果合并到一起。因为某种情况需要将几个SELECT语句查询出来的结果合并起来显示。使用UNION关键字时,数据库系统会将所有的查询结果合并到一起,然后去除掉相同的记录。而UNION ALL关键字则只是简单的合并到一起。其语法规则如下:

SELECT语句 1

UNION | UNION ALL

SELECT语句 2

查询结果取差集

SELECT语句 1

minus

SELECT语句 2

举例说明:

select * from a_xm t where t.xmdm = '8200842'

union

select * from a_xm t where t.xmdm = '8200842';

select * from a_xm t where t.xmdm = '8200842'

union all

select * from a_xm t where t.xmdm = '8200842';

举例说明:

select * from a_xm t where t.xmdm in ('8200842','8200951','8200952')

minus

select * from a_xm t where t.xmdm = '8200951';

五、SQL经典统计(oracle环境)

假设存在一个统计需求,统计某个时间段的物品采购量,如下表格所示:

第一步:先列出涉及后台业务数据表;

--1)采购单主表

select t.*, t.rowid from fh.a_cgd_m t;

--2)采购单从表

select t.*, t.rowid from fh.a_cgd_d t;

--3)项目基础表

select t.*, t.rowid from fh.a_xm t;

--4)生产厂家表

select t.*, t.rowid from fh.a_sccj t;

第二步:书写select语句基本格式,先各个表关联起来;

SELECT 属性列表 FROM 集合

WHERE 条件表达式 1

GROUP BY属性列表  HAVING 条件表达式 2

ORDER BY属性名  ASC | DESC

/*查询2014-01-01至2014-12-31采购物品汇总*/

Select ' ' "物品代码",

        ' ' "物品名称",

        ' ' "规格",

        ' ' "物品分类名称",

        ' ' "采购总数量",

        ' ' "单位",

        ' ' "批发单价",

        ' ' "批发总金额"

  from fh.a_cgd_m t1, fh.a_cgd_d t2, fh.a_xm t3

Where ...

第三步:从表中补齐对应字段,补齐不了的就留空,将相应的表关联起来

Select t2.xmdm "物品代码",

        t2.xmmc "物品名称",

        t3.guige "规格",

        t3.xmfl "物品分类名称",

        t2.sl "采购总数量",

        t2.xmdw "单位",

        t2.pfdj "批发单价",

        ' ' "批发总金额"

  from fh.a_cgd_m t1, fh.a_cgd_d t2, fh.a_xm t3, fh.a_sccj t4

Where t1.id = t2.id

            and t2.xmdm = t3.xmdm

            and t2.sccj = t4.dm

            and t1.ssysdate >= to_date('2014-01-01 00:00:00','yyyy-mm-dd hh24:mi:ss')

            and t1.ssysdate <= to_date('2014-12-31 23:59:59','yyyy-mm-dd hh24:mi:ss');

第四步:要对查询结果进行分类汇总。(使用集合函数查询,例如COUNT(), AVG(), MAX(), MIN(), SUM()等)。

Select t2.xmdm "物品代码",

      t2.xmmc "物品名称",

      t3.guige "规格",

      t3.xmfl "物品分类名称",

      sum(t2.sl) "采购总数量",

      t2.xmdw "单位",

      t2.pfdj "批发单价",

      sum(t2.sl * t2.pfdj) "批发总金额"

  from fh.a_cgd_m t1, fh.a_cgd_d t2, fh.a_xm t3, fh.a_sccj t4

Where t1.id = t2.id

  and t2.xmdm = t3.xmdm

  and t2.sccj = t4.dm

and t1.ssysdate >= to_date('2014-01-01 00:00:00','yyyy-mm-dd hh24:mi:ss')

  and t1.ssysdate <= to_date('2014-12-31 23:59:59','yyyy-mm-dd hh24:mi:ss')

group by t2.xmdm, t2.xmmc, t3.guige, t3.xmfl, t2.xmdw, t2.pfdj

order by t2.xmdm;

六、sql实践举例 (oracle环境)

1、decode和case when end与sum配合使用,可以简化sql语句的书写难度

举例说明:同时统计采购物品A、B、C、D分类的小计

2、case when使用

举例说明:同时统计某个科室的出库给中心药房的基数、节约的小计

sql语句部份截图

3、字段列表使用select进行转换

select ....,(select  decode(t.cyqk, '1','治愈','2','好转','3','未愈','4','死亡','5','24h内死亡','6','未治','7','其他')    from ndns.ycy t

        where t.jzh = t1.jzh) OutRemark   from ....

作用:1、1、简化sql的书写难度;2、避免集合产生一对多或多对多的关系

4、使用with关键字书写子查询

with

aa1 as ( select ... from ...),

aa2 as ( select ... from ...),

...

aan as ( select ... from ...)

select * from aa1,aa2,...,aan

这种方式类似编程里面的“上下文”写法。什么是上下文,举例说明:今天来到泰安,假设我现在跑到大街上,随便找个人跟他说,“先生/女士,等一下我们一起爬泰山”,别人会觉得很诧异,为什么,因为你和他之间缺少一个对话情境,如果今天我在这个会议现场,“有空我们一起爬泰山”,你会说“我考虑一下”,因为你们之间建立一种“我们都是医信同仁”对话情境,这样的对话才意义,这个对话情境就可以理解为上下文。

七、总结

     今天和大家一起回顾总结sql比较重要的东西,希望大家有所收获。另外我个人简书上还有2篇文章介绍了与sql相关的知识,《首届2019医信工程师创新大会参会感及重要分享补充》和《如何看待合理的HIT数据库表结构设计》,大家有兴趣可以去阅读一下。

   大家可以在微信公众号搜索关注“医信大讲堂”,这个是医信人务实分享交流的一个平台。还有我个人简书账号,我会不定期发布一些文章与大家分享,我们每个HIT工程师不断把经验分享出来回馈到HIT行业,我相信HIT行业将会越来越好。

医信大讲堂公众号 我的简书账号
上一篇 下一篇

猜你喜欢

热点阅读