
简介《天健医院信息系统数据结构手册》面向HIS实施、运维及数据库开发人员系统梳理天健医院信息系统的数据库表结构帮助不熟悉该系统的工程师快速定位字典表、人员属性、地区单位、科室配置等数据对象理解字段含义与表间关系。压缩包共1个doc文件约7.19MB以单一Word文档承载完整手册便于检索、打印和随项目归档内容按公共字典、人员信息、国家地区与合同单位、科室临床属性等模块组织并保留版本更新记录与字段状态标识说明。已有852人学习或下载适合在接口开发、数据查询、报表取数和老系统维护时作为表结构速查资料也能为梳理HIS数据标准化设计提供参考。1. 一份 2006 年的 HIS 数据结构手册老系统排障从哪张表下手接手一套跑了十几年的 HIS最先该要的不是源码是数据库表结构手册。我遇到过一次典型的翻车某个住院病人多收了一天床位费翻遍收费模块代码都找不到哪一步重复写了数据最后顺着表关系摸到病人在科记录和床位记录才发现是转科时旧床位没释放。如果手上有这么一份结构手册这事十分钟能定位。这份 2006 年定稿的第 15 稿覆盖了公共字典、病人主索引、医嘱、药品、检验、病案、门诊收费等十七个业务域几百张表标明了哪些在用、哪些新增、哪些已经废弃。它不是教程是一张地下管网图——正在维护、二次开发或者准备做数据迁移的工程师照着它才能判断一条数据该落在哪、从哪查出来、改动会波及谁。2. 手册的骨架十七个业务域与四类表的命名规律目录摊开是十七个大类从公共部分一路排到门诊收费每类下面一串表名。第一次看会觉得杂乱但它有一条很清楚的线索越靠前的越像基础数据一年改不了几次越靠后的越像流水数据每天几十万条往上涨。把这个分层认清楚备份策略、归档策略、索引加在哪张表上基本就有数了。2.1 十七类业务域按数据性质分层按手册的排序大致能切成五层章节范围业务域表数量级数据性质1–4人员属性、地区单位、医疗工作、疾病诊断与操作一百余张基础字典长期稳定5–6药品物资、费用价表六十余张主数据加价格版本敏感7–8系统维护、输入法二十余张平台级配置改动影响全局9–13病案、门诊病人、门诊医生、住院病人、医嘱七十余张核心业务流水14–17检查、检验、药品管理、门诊收费一百余张医技与库存资金流水第一层的特点是只增不改性别字典、婚姻状况字典这类表建好之后几乎不动但全院几百张业务表都拿它的编码做外键。第二层就麻烦了价表、药品字典是会被反复调价的所以手册里专门拆出了当前价表和价表两套结构。第四层是业务主干一个病人的所有诊疗行为都落在这里数据量大、关联多出问题也多半出在这。第五层是外围检验、检查、药品库存每块都有自己的主从结构。我一般会在拿到手册的第一天做一件事把每张表按这五层标一遍然后看数据库里每张表的实际行数。经常会出现字典表四十万行、流水表两万行的反常情况那就说明有人在拿字典表当业务表用或者历史数据压根没归档。2.2 表名后缀就是表的角色这套命名相当克制看懂后缀能省掉一半翻手册的时间后缀含义典型表改动风险_DICT编码加名称的字典表DEPT_DICT、DRUG_DICT低但要考虑停用标志_VS_两张表的多对多对照CHARGE_TYPE_VS_IDENTITY、DEPT_VS_WARD中改对照等于改业务规则_CONFIG配置项HOSPITAL_CONFIG、INSTRUMENT_CONFIG高全系统读_MASTER主记录EXAM_MASTER、DRUG_IMPORT_MASTER高_DETAIL/_ITEMS明细或子项DRUG_IMPORT_DETAIL、EXAM_ITEMS高_REC单条业务记录BED_REC、MR_REC中_LOG只追加的日志ADT_LOG、DRUG_STOP_LOG低别去更新它_T/_TEMP队列或临时表OUTP_ORDERS_T、LAB_RESULT_TEMP低可重建字典表的通用骨架长这样字段名按手册惯例示意具体以实际库为准-- 字典表的通用三件套编码、名称、有效标志 CREATE TABLE DEPT_DICT ( DEPT_CODE VARCHAR(8) NOT NULL, -- 科室编码业务表的外键 DEPT_NAME VARCHAR(64) NOT NULL, -- 科室名称 INPUT_CODE VARCHAR(16), -- 拼音或五笔检索码给下拉框用 DEPT_CLASS VARCHAR(4), -- 科室类别临床、医技、行政 VALID_FLAG CHAR(1) DEFAULT 1, -- 1 在用0 停用 MEMO VARCHAR(255), CONSTRAINT PK_DEPT_DICT PRIMARY KEY (DEPT_CODE) );这里有个血泪经验VALID_FLAG千万不要做成物理删除。老系统里一张停用科室的历史病历、历史医嘱全都指向这个编码删了字典行报表里全是空白科室名。正确做法是置 0然后所有下拉框查询统一加WHERE VALID_FLAG 1报表查询不加这个条件历史数据才能正常显示。INPUT_CODE也是个容易踩的点。有些实施人员为了让检索更快直接把它设成必填结果新加科室时拼音码生成不出来界面报错但后台没日志。这类字段应该允许空检索时用INPUT_CODE LIKE NK% OR DEPT_NAME LIKE %内科%兜底。2.3 颜色标注和不使用标记是文档自己的版本控制手册前言里写得很清楚红字标识的表和字段是未使用状态蓝字是新增且在用的黑字是在用的。表名后面还跟着(新增)、(不使用)、(针对某类医院)这类括号说明。这其实是当年没有 Git 的情况下文档维护者硬做出来的一套状态标记。这套标记的价值在于它能告诉你哪些表是历史包袱。《USERS》标着不使用《DOCTOR_ORDERS》标着不使用但真正危险的是那些手册里没标、代码里早就不写、数据库里却还留着触发器往外同步数据的表。我在一个项目里碰到过某张标注废弃的过敏药物记录表上挂着一个触发器一直往一张不存在的备份表插数据每次插入都报错被应用层静默吞掉了。排查这类问题靠的是元数据表手册第 7 章留着入口-- 查某张表在系统元数据里登记过哪些字段说明 SELECT TABLE_NAME, COLUMN_NAME, REMARK FROM TABLE_COLUMNS_SET WHERE TABLE_NAME DOCTOR_ORDERS ORDER BY COLUMN_NAME;TABLE_COLUMNS_SET、TABLE_ROLE_SET、TABLE_SYNONYM_SET这三张表是文档里的文档记录字段解释、角色解释和同义词。二次开发时改表结构最好同步往这里写一条不然半年后自己都忘了当初为什么加这个字段。参数说明很直白TABLE_NAME是物理表名COLUMN_NAME是列名REMARK是中文说明写得越细越好。3. 病人主索引链路PAT_MASTER_INDEX 到 TRANSFER 的完整走向一个病人从挂号到出院数据到底落在哪几张表里这是所有二次开发的第一课。这套 HIS 的答案很清晰主索引负责是谁就诊记录负责哪一次在科记录负责在哪个科待过日志表负责发生过什么。3.1 主索引是全院的唯一锚点住院号只是其中一段PAT_MASTER_INDEX是全院病人身份的唯一来源门诊、住院、检验、检查、病案所有业务表最终都通过病人标识号挂到这张表上。住院号、门诊号、医保号、就诊卡号都只是别名散落在各自的业务表里。这么设计的好处是同一个病人多次就诊能串起来坏处是一旦建档重复全院的费用、检验结果、病案就会分裂成两个人。手册里专门留了两张表来治这个病PMI_MERGED_LOG记录主索引合并PAT_MASTER_RENAME_LOG记录改名。-- 主索引表的核心字段示意 CREATE TABLE PAT_MASTER_INDEX ( PATIENT_ID VARCHAR(16) NOT NULL, -- 全院唯一病人标识业务主键 INP_NO VARCHAR(12), -- 住院号只在住院业务里用 OUTP_NO VARCHAR(12), -- 门诊号 NAME VARCHAR(32) NOT NULL, SEX_CODE CHAR(1), -- 关联 SEX_DICT BIRTH_DATE DATE, ID_NO VARCHAR(20), -- 身份证号查重的主要依据 CHARGE_TYPE VARCHAR(4), -- 费别关联 CHARGE_TYPE_DICT VALID_FLAG CHAR(1) DEFAULT 1, CONSTRAINT PK_PAT_MASTER_INDEX PRIMARY KEY (PATIENT_ID) );参数上要注意ID_NO这一列。早年很多医院允许空身份证建档尤其是急诊和新生儿所以查重绝不能只靠身份证。我一般的查重顺序是先按身份证精确匹配再按姓名 出生日期 性别模糊匹配最后人工确认。合并操作必须在事务里做先把所有业务表的PATIENT_ID改成主记录再往PMI_MERGED_LOG写一条从旧到新的映射最后把旧记录置为无效。这里要留个后悔药合并之前一定要把两条主索引及其所有关联记录导出成一份快照。合并做错了想拆回去没有快照就只能手工对账。3.2 一次住院的时间线PAT_VISIT、TRANSFER、BED_REC主索引知道是谁接下来要知道哪一次住院和在哪些科待过。这三张表的关系是PAT_VISIT每次住院一条主键通常是病人标识加住院次数记录入院日期、入院科室、出院日期、出院方式。TRANSFER病人在科记录一次住院里转几次科就有几条记录转入科室、转出科室、起止时间。BED_REC床位记录记录床号、床位状态、占用起止时间。PATS_IN_HOSPITAL在院病人快照表只保留当前在院的出院就删。ADT_LOG入出转日志只追加不更新是追溯的最后一根救命稻草。PATS_IN_HOSPITAL这张快照表是最容易被误用的。它查询快、关联少很多报表直接拿它当住院主表用结果一出院数据就没了月度报表永远对不上。正确姿势是实时看板查快照表任何需要回溯的统计查PAT_VISIT加TRANSFER。-- 查某病人一次住院的完整流转时间线 SELECT v.INP_NO, v.ADMISSION_DATE, t.FROM_DEPT_CODE, t.TO_DEPT_CODE, t.START_DATE_TIME, t.END_DATE_TIME, t.TRANSFER_REASON FROM PAT_VISIT v JOIN TRANSFER t ON t.PATIENT_ID v.PATIENT_ID AND t.VISIT_ID v.VISIT_ID WHERE v.PATIENT_ID :patientId AND v.VISIT_ID :visitId ORDER BY t.START_DATE_TIME;VISIT_ID这个参数是整个住院域的核心住院医嘱、检验申请、手术记录、病案首页全都带它。少了它同一个病人两次住院的数据就会串在一起费用对账直接崩。这也是我在做任何住院相关查询时第一个检查的字段。3.3 重复建档的排查要靠组合条件老库里主索引重复是常态尤其是早年没有实名制的时候。查重脚本不能太严也不能太松我一般用这套组合条件跑一遍人工看一眼结果-- 疑似重复主索引身份证相同或姓名生日性别相同 SELECT a.PATIENT_ID, a.NAME, a.ID_NO, a.BIRTH_DATE, b.PATIENT_ID AS DUP_ID, b.NAME AS DUP_NAME FROM PAT_MASTER_INDEX a JOIN PAT_MASTER_INDEX b ON a.PATIENT_ID b.PATIENT_ID AND ( (a.ID_NO IS NOT NULL AND a.ID_NO b.ID_NO) OR (a.NAME b.NAME AND a.BIRTH_DATE b.BIRTH_DATE AND a.SEX_CODE b.SEX_CODE) ) WHERE a.VALID_FLAG 1 AND b.VALID_FLAG 1;a.PATIENT_ID b.PATIENT_ID这个条件是为了避免自己跟自己配对、也避免 A-B 和 B-A 重复出现。跑完之后不要直接改数据先导出结果给病案室确认因为同名同生日的双胞胎在现实里真的存在。4. 医嘱、计价与药品库存三条最常被改坏的链路这三块是二次开发动得最多、也最容易出事的地方。医嘱决定了医生开什么计价决定了收多少钱药品库存决定了药房发得出发不出。三条链路各自独立又互相咬合改一处忘了另一处第二天财务就会找上门。4.1 医嘱和计价为什么必须拆成两张表新手最常见的疑问是一条医嘱不是对应一个价格吗为什么还要单独一张ORDERS_COSTS因为现实里一条医嘱经常对应多个收费项目。一台手术的医嘱可能拆成手术费、麻醉费、材料费、床位加收一次输液可能拆成输液费、注射器、药品本身。这种一对多的关系硬塞进医嘱表就只能加一堆FEE1、FEE2这样的字段最后没法维护。所以这套结构是ORDERS医嘱主记录存医嘱内容、开立医生、开立时间、停止时间、状态。ORDERS_COSTS医嘱计价项目一条医嘱对应一到多条每条关联价表项目编码和数量。ORDERS_EXECUTE医嘱执行记录护士每次执行打一条皮试、输液、口服都在这。OUTP_ORDERS/OUTP_PRESC/OUTP_TREAT_REC门诊侧的对应结构主记录加处方明细加检查治疗明细。-- 一条医嘱拆成多条计价的典型结构 CREATE TABLE ORDERS ( PATIENT_ID VARCHAR(16) NOT NULL, VISIT_ID VARCHAR(8) NOT NULL, -- 住院次数和 PAT_VISIT 对应 ORDER_NO VARCHAR(16) NOT NULL, -- 医嘱序号科室内唯一 ORDER_CLASS VARCHAR(4), -- 长期/临时关联 ORDER_CLASS_DICT ORDER_TEXT VARCHAR(255), -- 医嘱正文 START_DATE_TIME DATE, STOP_DATE_TIME DATE, ORDER_STATUS VARCHAR(4), -- 开立/执行/停止/作废 DOCTOR_CODE VARCHAR(8), CONSTRAINT PK_ORDERS PRIMARY KEY (PATIENT_ID, VISIT_ID, ORDER_NO) ); CREATE TABLE ORDERS_COSTS ( PATIENT_ID VARCHAR(16) NOT NULL, VISIT_ID VARCHAR(8) NOT NULL, ORDER_NO VARCHAR(16) NOT NULL, -- 挂回医嘱主记录 ITEM_CODE VARCHAR(16) NOT NULL, -- 价表项目编码 ITEM_CLASS VARCHAR(4), -- 费用分类关联 BILL_ITEM_CLASS_DICT AMOUNT DECIMAL(10,2), -- 数量 UNITS VARCHAR(8), -- 单位 COSTS DECIMAL(12,2), -- 金额 BILLING_DATE DATE, CONSTRAINT PK_ORDERS_COSTS PRIMARY KEY (PATIENT_ID, VISIT_ID, ORDER_NO, ITEM_CODE) );主键设计值得说一句(PATIENT_ID, VISIT_ID, ORDER_NO, ITEM_CODE)这个组合意味着同一条医嘱下同一个价表项目只能出现一次。如果业务上真需要重复就得靠数量字段合并不能插两条。有些实施人员图省事直接改成自增主键结果停嘱重开时同一项目插了两次费用翻倍这就是典型的翻车。4.2 价表版本化CURRENT_PRICE_LIST 和 PRICE_LIST 的分工价表是全院最容易引发纠纷的表。病人住院二十天中途某项检查调价了出院结算到底按哪天的价这套结构的答案是PRICE_LIST存历史全量价格CURRENT_PRICE_LIST只存当前生效价业务发生时以当时的价格写入ORDERS_COSTS或MEDICAL_COSTS之后价表怎么变都不回头改已结算数据。-- 按调价日期取某项目在指定时点的有效价格 SELECT p.ITEM_CODE, p.ITEM_NAME, p.PRICE, p.START_DATE, p.STOP_DATE FROM PRICE_LIST p WHERE p.ITEM_CODE :itemCode AND :bizDate BETWEEN p.START_DATE AND NVL(p.STOP_DATE, DATE 2099-12-31) ORDER BY p.START_DATE DESC;START_DATE和STOP_DATE构成一个时间区间NVL把未设结束日期的记录当成长期有效。这个查询在费用补录、退费重算的场景里天天要用。参数bizDate一定是业务发生日期不是当前日期——这一点错一次就是几千块的差额。手册里还有几张和价表配套的表值得记住CLINIC_VS_CHARGE是临床诊疗项目和价表项目的对照PERFORM_DEPT指定价表项目的执行科室CHARGE_PRICE_SCHEDULE存收费系数。改价表结构时这三张必须同步检查不然会出现项目能开、费用算不出来、执行科室为空的怪状态。4.3 药品库存的主从账与结转药品域的链路比医嘱更长字典 → 库存 → 入库 → 出库 → 发药 → 结转 → 总账。手册里光药品管理就列了五十多张表但真正撑起库存准确性的只有这几张DRUG_DICT药品字典编码、名称、规格、剂型、毒理分类、处方属性。DRUG_STOCK当前库存按药房、货位、批号记录数量和金额。DRUG_IMPORT_MASTER/DRUG_IMPORT_DETAIL入库主从表。DRUG_EXPORT_MASTER/DRUG_EXPORT_DETAIL出库主从表。DRUG_LEDGER药品总账每次出入库都追加一条。DRUG_STOCK_BALANCE结转记录月末结账用。-- 校验某药房某药品的库存是否与总账一致 SELECT s.DRUG_CODE, s.STORAGE_DEPT, SUM(s.QUANTITY) AS STOCK_QTY, (SELECT SUM(l.IN_QTY - l.OUT_QTY) FROM DRUG_LEDGER l WHERE l.DRUG_CODE s.DRUG_CODE AND l.STORAGE_DEPT s.STORAGE_DEPT) AS LEDGER_QTY FROM DRUG_STOCK s WHERE s.STORAGE_DEPT :storageDept GROUP BY s.DRUG_CODE, s.STORAGE_DEPT HAVING SUM(s.QUANTITY) (SELECT SUM(l.IN_QTY - l.OUT_QTY) FROM DRUG_LEDGER l WHERE l.DRUG_CODE s.DRUG_CODE AND l.STORAGE_DEPT s.STORAGE_DEPT);这个查询我一般做成月度巡检脚本。STOCK_QTY是库存表实际数量LEDGER_QTY是总账累计进减出两者不等就说明有业务漏写了总账或者有人直接改了库存表。HAVING里只留差异行正常情况下应该返回空结果集。参数storageDept是药房编码多药房要分开跑。还有一个坑是批号。DRUG_STOCK按批号分行存但很多查询忘了按批号分组直接SUM(QUANTITY)看起来总数对得上实际效期管理全乱了。发药时先进先出靠的就是批号和效期这个字段丢了药房迟早出问题。5. 避坑与排查老 HIS 数据库里五个反复踩的坑下面五条是我在不同项目里反复遇到的每一条都按现象、原因、解决办法写遇到类似的直接对号入座。5.1 检索码和字符集拼音码查不出病人现象门诊挂号界面输入病人姓名的拼音首字母搜不到人但直接输汉字能搜到。新入职的同事以为是索引问题加了一堆索引还是没用。原因老库用的是 GBK 字符集检索码在入库时由程序生成并写进INPUT_CODE字段。后来系统迁移到 UTF-8历史数据的检索码还在新数据的检索码生成逻辑因为字符集判断失效全部写成了空。于是新病人搜不到老病人正常。解决分两步。先补数据用脚本按姓名重新生成一遍检索码覆盖INPUT_CODE为空的记录再修程序把生成逻辑里的字符集判断去掉统一按 Unicode 处理。补数据之前先备份整张表因为拼音多音字生成结果不一定和老系统一致要抽样比对。另一类同源问题是OUTER_CODE_DICT输入码表。这张表存的是各种输入法的编码映射手册第 8 章整章都在讲输入法配置。迁移字符集时忘了重建这张表五笔用户会集体反馈打不出字。5.2 时间字段的类型陷阱跨年查询漏数据现象年度统计报表比实际少了十二月最后几天的数据逐月核对又都对得上。原因部分历史表的时间字段是字符型格式是YYYY-MM-DD HH:MI:SS查询时用BETWEEN 2023-01-01 AND 2023-12-31字符比较把2023-12-31 08:00:00排在了2023-12-31之后直接漏掉。更隐蔽的是有的表混用两种格式月和日补没补零不一致字符串排序完全错乱。解决查询统一用TO_DATE显式转换或者写成 起始日 AND 次日零点的半开区间。改造老表时把字符型时间列逐步换成日期型但要先确认所有写入方都跟着改否则会出现隐式转换失败。我一般的规矩是新写的任何查询时间条件一律半开区间不给自己留隐患。5.3 快照表和流水表不一致在院人数对不上现象住院处报的在院人数和病区护士站看到的对不上差几个人过一天又对上了。原因PATS_IN_HOSPITAL是快照表PAT_VISIT是流水表。出院操作如果是先删快照再更新流水中间有任何异常比如网络中断、事务回滚不完整两张表就脱节了。反过来先更新流水再删快照短暂的中间态又会让统计口径不一致。解决把两张表的维护放进同一个事务顺序固定为更新流水 → 删快照 → 写ADT_LOG任何一步失败整体回滚。再配一个每日巡检脚本用PAT_VISIT里未填出院日期的记录去比对快照表找出差异人工修正。ADT_LOG在这里是最后一根救命稻草它是只追加的能还原出到底哪一步没执行。5.4 废弃表还在被写触发器埋的雷现象一张手册里标着不使用的表数据量每天都在涨而且里面全是脏数据。原因早年某个模块在这张表上挂了触发器往另一张表同步数据。模块下线了触发器没删只要有其他地方往这张表插数据触发器就执行一次写进一张早就不存在的目标表报错被应用层吞掉。解决先把数据库里所有触发器和存储过程列一遍逐个确认业务归属。确认废弃的先禁用而不是直接删观察一周没有异常再清理。同时把手册里的不使用标记补上具体日期和原因别让下一个人再猜。5.5 金额精度退费退出一分钱差额现象病人退费时退的金额和原来收的差一分钱财务对账天天有零星差异。原因金额字段有的是NUMBER(12,2)有的是FLOAT还有的是程序里用浮点数算完再写库。浮点累加会产生0.009999这样的尾数四舍五入后差一分。住院费用动辄几十条明细累加起来差异就明显了。解决所有金额字段统一成定点小数运算全部在数据库里用DECIMAL完成程序侧只做展示不做计算。已经存在浮点字段的表做一次全量重算把明细金额和主记录总额对齐。这个改造动作大必须挑业务低峰期做改造前后各跑一次总额比对。6. 二次开发改造加字段、加字典、做数据校验的稳妥做法在这套结构上做二次开发最容易犯的错是就加个字段很快。加字段本身确实快难的是加完之后所有读这张表的地方都得知道它。我目前的习惯是三步走。第一步先确认这张表属于哪一层。字典表加字段影响面小流水表加字段要考虑历史数据怎么补默认值主从表加字段要主从一起加。第二步字段名带前缀比如给住院主记录加个扩展属性就命名成EXT_开头一眼能看出是二次开发加的不是原厂字段。第三步同步往TABLE_COLUMNS_SET里写一条中文说明写清楚加的时间、用途、谁在用。加字典表要更谨慎。手册里留了一张META_DATA简易字典代码表很多下拉框的选项就是从这来的。新增一个业务字典优先复用它而不是新建表否则字典表会越堆越多最后没人说得清哪张在用。真需要独立成表就按_DICT后缀加编码、名称、检索码、有效标志这四件套来保持风格统一。数据校验这块我一般会写一个巡检脚本集每天凌晨跑一遍结果发到工作群。核心就三类巡检项检查逻辑异常含义主索引重复身份证或姓名生日性别组合重复建档流程有漏洞医嘱无计价ORDERS有记录但ORDERS_COSTS无对应计价规则漏配库存账实不符DRUG_STOCK与DRUG_LEDGER累计不一致出入库漏写总账每条巡检出结果之后不要自动修数据只出报告。自动修数据看着省事一旦规则写错就是批量污染恢复起来比重录还慢。最后一个技巧做任何涉及费用或库存的改造先在测试库跑一遍改造前查询和改造后查询把两份结果做全量 diff差异行逐条确认。这个动作我坚持了很多年因为它拦下过至少三次上线事故——有一次是改价表关联条件时漏了一个有效期判断diff 直接暴露了三千多条价格差异。从那以后我每次动这几张核心表都强制走一遍导出快照、跑 diff、留回滚脚本的流程再急也不跳过。希望帮到你。本文还有配套的精品资源点击获取