简介:《东华his表结构新版.docx》是一份面向医院信息系统(HIS)研发、运维及数据对接人员的表结构说明文档,针对东华HIS核心数据模型进行了系统梳理。文档按业务域划分章节,覆盖CSP组件表、用户信息表、病人登记信息表、就诊卡记录与就诊卡类型表、病人基本信息主表,以及婚姻状况、性别、职业、宗教、学历、民族等基础字典表;同时详细说明医嘱项目定义、医嘱子类、医嘱大类、医嘱执行分类,以及医嘱套、医嘱优先级、医嘱状态等关联表,并涉及账单组表与账单小组表的费用归类逻辑。每张表均列出序号、编码、名称、录入时间等关键字段,部分核心表还补充了业务含义与表间关系,例如HIS医嘱项与LIS医嘱套的对应方式,以及病人医嘱记录明细与收费项目明细的区分,可为二次开发、数据字典维护、接口联调与历史数据梳理提供直接参考。资源包内只有1个docx文件,压缩包大小约92KB,内容为纯文本表格描述,便于检索和对照。发布以来已有1656人学习下载,适合医院信息科工程师、HIS实施顾问以及需要了解东华表结构的医疗数据开发人员收藏使用。
1. 东华HIS表结构新版:这份 docx 是比源码更好使的接口地图
做东华 HIS 二次开发,最怕的不是业务复杂,是拿到一个需求后不知道数据在哪张表。这份“东华his表结构新版.docx”我拆完后的感受是:它几乎把 DHC-APP 命名空间里从患者登记、就诊、医嘱到收费结算的主干表都按模块列出来了,字段注释写得很直白,连关联表都标注了方向。适合三类人:刚接手东华 HIS 的 Java 或 .NET 工程师、做 ETL 或数据分析的取数人员、还有要跟东华做接口联调的第三方实施。它解决的核心问题只有一个——别让「表名在哪」拦住你的开发进度。这份文档本身是 docx 格式,Windows 搜索都能直接搜正文,查找字段很快。
2. 先看清整体:东华HIS表结构的分层逻辑与核心关联
2.1 为什么字段名里全是_DR:Caché持久类留下的习惯
东华HIS跑在InterSystems Caché(新版本是IRIS)上,这张docx里的表名和字段名大多不是传统MySQL那种人工设计的命名,而是直接从持久类映射出来的。你看到的PA_Patmas、PA_Adm、SS_User,本质上是持久类名;每一个属性在SQL层被映射成字段。
这里最关键的是外键的表示方式。普通关系库里我们习惯用user_id、dept_id这种字段,但Caché里对象引用属性被映射成_DR结尾的字段,比如PAADM_PAPMI_DR指的是PA_Adm这个类里指向PA_Patmas对象的引用。你不需要纠结命名来源,只需要记住一条规则:凡是以_DR结尾的字段,大概率是关联另一张表的RowId,查询时要顺着它去JOIN目标表。
还有一类ParRef字段,在文档里没有直接列出来,但子表一般会通过ParRef指向父表。比如医嘱子表OE_OrdItem大概率有一条字段指向OE_Order。你从文档里看不到这列,是因为它属于类关系中的“内嵌引用”而不是普通属性。遇到这种情况,我会在IRIS管理门户里打开对应类的属性列表,搜ParRef就能找到。做表结构梳理时,别只盯着docx里列出的字段,还要补上这一层隐藏关系,否则JOIN会断。
提示:Caché的表名和字段名默认不区分大小写,但为了可读性,最好和文档保持一致。在SQL查询里可以不加引号直接写。
2.2 从PA_Patmas到PA_Adm:病人主数据怎么串起来
文档中病人相关的表分成两层:PA_Patmas(病人登记信息表)和PA_Person(病人基本信息主表)。PA_Patmas存的是每一次建档产生的登记号、姓名拼音、身份证号、VIP标志、黑名单标志;PA_Person则继续装地址、婚姻、职业、学历、民族、宗教这些明细主数据。两层之间通过PAPMI_PAPER_DR关联,也就是PA_Patmas的PAPMI_PAPER_DR指向PA_Person的PAPER_RowId。
这里有个容易看晕的点:性别、婚姻、职业、学历这些字段并没有直接放中文名称,而是分别指向CT_Sex、CT_Marital、CT_Occupation、CT_Education等字典表。比如PAPER_Sex_Dr关联CT_Sex的CTSEX_RowId。这类基础字典表字段很简单,基本都有RowId、Code、Desc三板斧。你在出报表时如果不JOIN字典表,查出来的就是一个RowId数字,落到Excel里全是“性别:5”,这种坑我在需求评审时见过很多次。
就诊记录主表是PA_Adm,在文档里也写作PA_Adm_User.PAAdm。一次就诊(门诊、急诊、住院)都会在这里有一行记录,包括就诊号PAADM_ADMNo、就诊日期、就诊类型PAADM_Type、访问状态PAADM_VisitStatus、就诊科室、医生、床位、病区等。PA_Adm通过PAADM_PAPMI_DR关联PA_Patmas,通过PAADM_DepCode_DR关联CT_LOC科室,通过PAADM_AdmDocCodeDR关联CT_CareProv医生。这条链路是整份文档里最常被查询的,读透了后面看医嘱、收费都顺。
就诊记录表里的PAADM_AdmReason_DR其实指向诊断相关表,但文档里写得很含糊。实际在需求里如果要把“本次就诊的初步诊断”带出来,要走PAADM_MainMRADM_DR转到病历相关表,而不是直接在PA_Adm里翻。这块等做到病案首页时再细抠,第一轮梳理不用深入到诊断链。
2.3 用SQL把核心关系拉出来:三个必查查询
我一般会先跑三个查询,把整张表结构文档的骨架验证一遍。第一个是“病人最近就诊记录”,把PA_Patmas、PA_Adm、CT_CareProv三张表串起来。下面这段SQL在Caché的SQL Shell里可以直接跑:
SELECT pa.PAPMI_No AS 登记号, pa.PAPMI_Name AS 姓名, adm.PAADM_ADMNo AS 就诊号, adm.PAADM_Type AS 就诊类型, adm.PAADM_VisitStatus AS 状态, adm.PAADM_AdmDate AS 就诊日期, doc.CTPCP_Desc AS 医生姓名 FROM PA_Adm adm JOIN PA_Patmas pa ON adm.PAADM_PAPMI_DR = pa.PAPMI_RowId JOIN CT_CareProv doc ON adm.PAADM_AdmDocCodeDR = doc.CIPCP_RowId WHERE pa.PAPMI_No = '000123456' ORDER BY adm.PAADM_AdmDate DESC这段SQL里PA_Adm是表名,PAADM_PAPMI_DR是外键字段,PA_Patmas的登记号字段是PAPMI_No而不是PAPMI_Code。PAADM_Type的含义文档写得很清楚:O是门诊,E是急诊,I是住院,T是体检。PAADM_VisitStatus也要注意:A是当前在院,C是撤销,D是出院未收费,P是预住院,R是离院,N是未签到。之前有同事把D直接理解成出院,结果统计住院人次时把门诊撤销的记录也算进去了。
第二个查询是“科室树”,从CT_LOC取科室编码、科室名称、类型。这个查询主要用于确认当前环境里有哪些病区、门诊诊室、执行科室。第三个查询是“字典表核对”,随便挑CT_Sex查一次,确认字典表的Code和Desc能对上。这三个查询只要跑通,说明你的连接账号、表名映射、基础权限都没问题,后面再按业务模块逐步展开。跑不通的时候,优先检查是不是把Caché类名写成了SQL表名,比如PA_Patmas是类名,直接作为SQL表名没问题,但要注意命名空间,默认在SQLUser下看不到。登录时用DHC-APP命名空间,或明确写成SQLUser.PA_Patmas。
3. 医嘱与收费:从“开什么医嘱”到“收多少钱”的表关系
3.1 医嘱项、医嘱套、收费项:先分清三个概念
文档在“医嘱项、医嘱套、LIS外部代码、医嘱记录”这部分,开篇就点了一句很值得琢磨的话:HIS医嘱项就是LIS的医嘱套,而HIS的医嘱套则是将常用的医嘱项组合而成的。我理解下来是这样:在检验科对接LIS的时候,LIS里的一个检验组合套餐,在HIS里表现为一条医嘱项;而医生工作站里的“医嘱套”是把多个医嘱项打包成一组常用操作,比如“入院常规”里面放血常规、尿常规、肝功能。
所以你在查数据时,先分清楚你要找的是哪一层。ARC_ItmMast是医嘱项目定义表,包含编码、名称、缩写、最小价格、最大价格、停用标志、医嘱子类、账单组等。这张表是基础字典,本身不包含某个病人的任何数据。它和收费项目是两套体系:医嘱项要跟收费项目关联后,医生开医嘱界面才能看到。这句话在文档里也出现过,意思是ARC_ItmMast里的项目如果没有在收费项目关联表里挂关系,开单界面不会显示。
这里还要注意一个容易混淆的地方:医嘱大类、医嘱子类、执行分类、账单组,这些分类维度是不同视角。医嘱大类是“材料、放射、检查、治疗”这种业务归属;医嘱子类是“放射材料、金卡材料、放射CT、加速器CT”这种收费小类;账单组则是“挂号费、西药费、中药费”这种与发票打印、财务核算相关的维度。ARC_ItmMast通过ARCIM_ItemCat_DR关联医嘱子类,通过ARCIM_BillSub_DR关联账单组。你写统计SQL时,选择哪个分类字段取决于需求是看医疗行为还是看财务收入。
3.2 病人的医嘱记在哪里:OE_Order与OE_OrdItem
文档里PA_Adm字段的注释中出现了“由表13-1 OE_Order -> OEORD_Adm_DR关联”,以及“由表13:OE_OrdItem -> OEORI_ItmMast_DR关联”,这就把医嘱主表和医嘱明细表的锚点给出来了。OE_Order大概是每次开立医嘱的“单头”,记录就诊关联;OE_OrdItem是“医嘱明细”,记录每一条具体医嘱项目。所有门诊处方、住院医嘱都在OE_OrdItem里,但文档特别提醒:这张表只记录病人医嘱,并不记录病人收费项目明细,收费明细要再往下走到收费项目记录表。
长期医嘱的处理方式也需要留意。文档里写:对于长期医嘱,在就诊明细中只存一条记录,然后在医嘱执行情况表中记录每次的执行时间。这和你看到的“每天自动执行”的长期医嘱场景是对应的。因此如果你要统计某条长期医嘱实际执行了多少次,就不能在OE_OrdItem里数行数,而要JOIN医嘱执行情况表去数执行次数。
医嘱状态、优先级、护士执行状态这几个维度是分开的。文档专门提到“医嘱状态这个比较有用,在查询检验记录时要查询该状态是否是正常状态”。如果你从LIS拉回报告后要过滤已作废的医嘱,就一定要先通过医嘱状态表确认,否则会把撤销的检验单也算成有效申请。我在做检验报告接口时,就曾经因为漏过滤作废状态,导致未执行的项目出现在已出报告列表里。
3.3 用一条SQL走通“查询病人住院长期医嘱及状态”
由于文档里OE_OrdItem的字段没列全,我这里给一段按文档已知字段推导的查询,重点在JOIN思路,具体字段名要按现场版本微调。第一步先查当前在院的住院就诊:
SELECT PAADM_RowID, PAADM_ADMNo, PAADM_PAPMI_DR, PAADM_AdmDate FROM PA_Adm WHERE PAADM_PAPMI_DR = ? AND PAADM_Type = 'I' AND PAADM_VisitStatus = 'A'拿到PAADM_RowID后,再通过OE_Order的OEORD_Adm_DR去关联,然后从OE_OrdItem里取具体医嘱项。如果现场版本里OE_OrdItem没有直接外键指向PA_Adm,通常会通过OE_Order中转,或者使用就诊明细关联表。下面这段SQL在大部分东华现场可以跑,但字段名需要核对:
SELECT adm.PAADM_ADMNo AS 就诊号, oe.OEORD_RowID AS 医嘱单号, oi.OEORI_ItmMast_DR AS 医嘱项ID, itm.ARCIM_Desc AS 医嘱项名称, oi.OEORI_StartDate AS 开始日期, oi.OEORI_StartTime AS 开始时间 FROM OE_OrdItem oi JOIN OE_Order oe ON oi.OEORI_OEORD_ParRef = oe.OEORD_RowID JOIN PA_Adm adm ON oe.OEORD_Adm_DR = adm.PAADM_RowID JOIN ARC_ItmMast itm ON oi.OEORI_ItmMast_DR = itm.ARCIM_RowId WHERE adm.PAADM_PAPMI_DR = ? AND adm.PAADM_Type = 'I'代码里OI.OEORI_OEORD_ParRef是我按Caché子表命名习惯补的,如果你在现场发现没有这个字段,就在管理门户里看OE_OrdItem的属性定义,找到指向OE_Order的引用字段。ARC_ItmMast的字段名是文档里确认过的,ARCIM_RowId作为主键,ARCIM_Desc作为医嘱项名称。这条SQL的要点是带着“就诊号”和“医嘱项ID”两个结果往下游走,后面接收费明细时,就用医嘱项ID去关联收费项关联表,不要直接拿OE_OrdItem去JOIN账单。
4. 把 docx 表结构变成自己的开发字典:整理、对比、建查询
4.1 从 docx 到 Excel:手工整理字段清单的方法
这份docx虽然已经是结构化表格,但它是按Word文档阅读顺序组织的,不是按字段查询场景组织的。我会在开工第一天先把所有表格复制到Excel里,每张表一个Sheet,列结构统一为:表名、表中文名、字段名、字段含义、关联表、关联字段、备注。Word里复制过来的表格一般会带“表1:websys.Component”这种标题行,转Excel后需要手工清洗一遍。
具体做法是这样的:先在Word里用“导航窗格”按一级标题定位到模块,然后按模块逐个复制表格;粘贴到Excel后,把第一列表头里的“表 6:ARC_ItmMast”提出来作为Sheet名,再在每张表的第一行插入“表名”列填上这个名称。字段列表里如果出现“关联字段----CTLOC_RowID”这种文本,用Excel的“分列”功能按“----”拆分,把关联目标拆到独立列里。这样出来的Excel字典,比直接翻docx快得多。
有条件的,还可以把Excel字典导入到数据库里做元数据表,这样后续可以在SQL里直接查“哪个字段关联了CT_LOC”。在MySQL或者SQL Server里建一张三列表,列名放表名、字段名、关联表,然后导入清理后的Excel。做ETL的人会更习惯这个方式。如果不想建库,Excel的筛选也够用,重点是把“关联表”那一列做出来。
4.2 用生产库反向核对:字段缺失和类型差异
拿到docx后不要直接信所有字段真实存在。东华在不同医院做过很多定制版本,同一张PA_Adm在A医院有PAADM_Isolation字段,在B医院可能没有。我一般会把docx里的表名整理成清单,然后在生产库的管理门户里逐表跑一句SQL确认字段。如果库允许用ODBC连外部工具,可以用Navicat或DB Studio看列清单。
用Navicat导出表结构这个操作很简单:连接到Caché/IRIS的数据源后,选中目标表,右键“导出表结构”,可以导成SQL脚本或Excel。但这类工具导出的只是物理列,不含业务注释,所以更适合用来核对“这张表到底有没有这个字段”。我自己最常用的是IRIS管理门户的SQL页面,执行下面这段查询看列名:
SELECT COLUMN_NAME, DATA_TYPE, ORDINAL_POSITION FROM INFORMATION_SCHEMA.COLUMNS WHERE TABLE_NAME IN ('PA_Adm', 'PA_Patmas', 'OE_OrdItem') ORDER BY TABLE_NAME, ORDINAL_POSITION需要说明的是,Caché的INFORMATION_SCHEMA在部分版本里表是在INFORMATION_SCHEMAschema下,但更稳妥的方式是查%Library的类定义或直接在管理门户看目录。如果你在Navicat里连的是ODBC DSN,上面的INFORMATION_SCHEMA也能用,只是schema名可能显示为SQLUser。遇到查不到的时候,退回到管理门户的“SQL”页面,使用“Actions -> Catalog Details”查看字段。
4.3 需要现查字段?Windows 搜索和工具导出的互补
这条给不太喜欢翻表的同事:docx可以直接被Windows搜索索引正文。你在资源管理器搜索框里输入PAADM_Type,系统能直接定位到这份文档,因为docx正文是能被索引的。这个方法特别适合那种“我记得一个字段名,但忘了它在哪一章”的情况。配合Word内置的高级查找,输入字段名后回车,光标会跳到对应表格,效率很高。
但Windows搜索对docx正文的索引受限于文件位置和索引选项,如果搜不到,把文件放到文档库或桌面再重建索引。还有一种情况是字段名太短,比如Code、Desc这种常见词,搜出来一堆结果。这时候我建议用Excel整理后的字典,在字典里按“字段含义”筛选,比全文搜索更快。工具导出的物理结构只能回答“有什么字段”,docx里的人工注释才能回答“字段什么意思”,两者互补,缺一个都会踩坑。
5. 避坑:东华HIS表结构里的五个经典翻车点
5.1 现象:两个表之间的_DR双向指向,JOIN后数据翻倍
有次我写一个查询,从PA_Patmas关联PA_Person取婚姻状况,把PAPMI_PAPER_DR和PAPER_PAPMI_DR两个方向都JOIN了,结果每个病人出现两条重复记录。原因是文档里PA_Patmas有字段PAPMI_PAPER_DR指向PA_Person,PA_Person里又有PAPER_PAPMI_DR反指PA_Patmas,对象关系模型里这叫双向引用。解决方法是只按一个方向JOIN,具体从哪边出发取决于当前主表。查病人基本信息时,从PA_Patmas左连接PA_Person,用PAPMI_PAPER_DR;查PERSON反查登记记录时,才用PAPER_PAPMI_DR。别在两个表之间同时写上双向条件,否则行数直接翻倍。
5.2 现象:SS_User密码查询出来是一串密文,没办法做明文比对
文档里明确写了SSUSR_Password是加密的,加密方法是DHC-MEDSRC空间下M程序$$ENCR^SSUTIL2("123"),所以别指望SELECT语句能直接看到明文。现象是你拿一个用户输入的密码去查,发现和库里完全不匹配。原因是这是单项加密,不是可逆的,正确的做法不是解密,而是把用户输入的密码也用同一个函数加密后再去比对。常见做法是在服务端调用$$ENCR^SSUTIL2,或者直接复用东华自带的登录校验接口,不自己写密码比对逻辑。特别注意:不同空间下M程序可见性不同,如果你在DHC-APP下调用不到SSUTIL2,需要加上DHC-MEDSRC的引用名。
5.3 现象:就诊号OP/IP开头含义和常识相反
文档在PA_Adm字段解释里写的是“OP起头的是住院就诊号、IP起头的是门诊就诊号”,很多第一次接触的工程师看到这个就懵了。OP不是Outpatient吗?IP不是Inpatient吗?怎么反过来了?我核实过的东华现场确实存在这种命名历史,不同医院可能不一致。解决方法是不要靠前缀猜,直接看PAADM_Type字段来判断就诊类型:O表示门诊,E表示急诊,I表示住院,T表示体检。你在导出数据时如果非要把OP/IP当作判断条件,一定先在当前环境里跑一条SELECT TOP 10 PAADM_ADMNo, PAADM_Type FROM PA_Adm验证一下。
5.4 现象:查病人费用时,在OE_OrdItem里看不到金额
有一个常见需求是“统计某病人这次住院花了多少钱”,新手通常直接查病人医嘱记录明细OE_OrdItem,结果发现里面只有医嘱项目和开始时间,根本没有收费金额。文档里已经点破:医嘱明细表只记录病人医嘱,并没有记录收费项目明细。解决方法是按文档三层结构走:PA_Adm先关联病人账单表,拿到账单RowId;再从病人账单关联的医嘱表找到医嘱记录;最后从病人账单关联的收费项记录表取出收费项目明细。这中间千万不要在OE_OrdItem和收费明细之间做笛卡尔连接,否则金额会被放大好几倍。我在做住院费用汇总时,是按“账单-医嘱-收费项”合并后再去重,这样金额才准确。
5.5 现象:统计科室时,同一张CT_LOC把医生诊室和病区都混在一起
CT_LOC是科室表,但它的类型字段CTLOC_Type把执行科室、手术室、其他、配送分发、病区、财务、门诊诊室、急诊科室全放在了一起。我见过一个统计全院科室数量的SQL,直接COUNT(*) FROM CT_LOC,结果跑出来几百条,里面一大半是病区护理单元和收费处。原因就是没过滤类型。解决方法是先根据需求定清楚“科室”范围:如果要统计医疗科室,至少要排除W(病区)、C(财务)、D(配送)等类型。文档里给出的值是:E执行科室、OP手术室、O其他、D配送分发、W病区、C财务出纳、OR门诊诊室、EM急诊科室。每次写科室统计前,先把CTLOC_Type枚举值列到需求文档里确认,不要默认所有行都是科室。
6. 进阶:把表结构文档变成接口开发与数据同步的路线图
6.1 从表结构反推CSP接口入参出参
当你接到一个“新增预约挂号”或“查询检验报告”需求时,docx里的表结构就是接口契约的底稿。比如查询检验报告,文档提示“医嘱标本记录与检验系统发生联系”“报告单存放路径对于LIS接口的HIS系统存放”,这时候你就知道出参里至少要有医嘱状态、报告路径、执行状态三个字段。先沿着表关系把数据链路画出来,再反推入参是哪个RowId,出参要带哪些字段,比直接翻CSP组件代码快得多。
6.2 用RowId和LastUpdateDate做增量同步的边界
数据抽取时,很多人会用RowId做增量标识,但RowId在Caché里是内部对象标识,删除数据后不会重用,而且不同表之间RowId没有全局唯一规则。文档里部分表有LastUpdateDate和LastUpdateTime,比如websys.Component、CT_Marital这些维护性基础表,但业务表不一定都有。做增量同步时,优先看表里有没有UpdateDate字段;没有的话,只能结合就诊日期或医嘱开始时间取增量窗口,并接受可能有延迟修改数据漏掉的风险。
6.3 一个验证习惯:每次接手先跑一遍字段核对
从那以后我每次接手新HIS现场,都强制自己走一遍:把docx里的表名批量粘到Excel,然后在IRIS管理门户逐表执行SELECT TOP 1 * FROM 表名,对照列名是否一致。不一致的列记下来,查询时绕开。这套动作十分钟做完,却能避免后续一整天调试SQL字段名拼写问题。希望帮到你。
本文还有配套的精品资源,点击获取