寧電子病歷表結(jié)構(gòu)拆解:HIS對(duì)接與SQL查詢實(shí)戰(zhàn)指南)
簡(jiǎn)介衛(wèi)寧電子病歷表結(jié)構(gòu)文檔面向醫(yī)院信息管理者、IT技術(shù)人員及醫(yī)療信息化研究人員系統(tǒng)梳理了衛(wèi)寧EMR 5.0的數(shù)據(jù)庫(kù)設(shè)計(jì)框架幫助讀者理解臨床信息系統(tǒng)的數(shù)據(jù)模型與標(biāo)準(zhǔn)化規(guī)范。資源包內(nèi)含1個(gè)doc文件約13.92MB完整收錄800余張數(shù)據(jù)表的說(shuō)明、字段定義、類(lèi)型、長(zhǎng)度及值域備注。內(nèi)容覆蓋系統(tǒng)框架、財(cái)務(wù)收費(fèi)、醫(yī)療信息與數(shù)據(jù)標(biāo)準(zhǔn)化等模塊如職工代碼庫(kù)、醫(yī)療項(xiàng)目庫(kù)、藥品分類(lèi)庫(kù)、科室與病區(qū)代碼庫(kù)以及憑證類(lèi)型庫(kù)、收費(fèi)大項(xiàng)目庫(kù)、醫(yī)保分類(lèi)庫(kù)、診斷代碼庫(kù)、職稱(chēng)編碼庫(kù)等并涉及權(quán)限管理與數(shù)據(jù)加密等安全設(shè)計(jì)。已有1543人學(xué)習(xí)下載適合用于優(yōu)化系統(tǒng)結(jié)構(gòu)、排查數(shù)據(jù)交換問(wèn)題及開(kāi)展醫(yī)療大數(shù)據(jù)分析是掌握衛(wèi)寧EMR底層表結(jié)構(gòu)的重要參考。1. 衛(wèi)寧電子病歷表結(jié)構(gòu).doc一份讓 HIS 對(duì)接少走彎路的拆解思路手上拿到一份「衛(wèi)寧電子病歷表結(jié)構(gòu).doc」多數(shù)人的第一反應(yīng)是翻目錄找字段但真正做過(guò)醫(yī)院信息系統(tǒng)對(duì)接的都知道這份文檔的價(jià)值不在字段清單本身而在于它決定了你后面寫(xiě) SQL、做視圖、跑數(shù)據(jù)同步時(shí)會(huì)不會(huì)踩到坑。衛(wèi)寧健康的電子病歷產(chǎn)品線在國(guó)內(nèi)三級(jí)醫(yī)院占有率很高圍繞它的表結(jié)構(gòu)做二次開(kāi)發(fā)、數(shù)據(jù)抽取、質(zhì)控分析是很多醫(yī)療 IT 從業(yè)者的日常。這篇文章不講空泛概念而是把這份表結(jié)構(gòu)文檔拆成能直接落地的路徑先搞清楚它的組織邏輯再講怎么從文檔里提取關(guān)鍵表關(guān)系最后落到查詢、同步和避坑的具體操作。適合正在做電子病歷數(shù)據(jù)對(duì)接、質(zhì)控指標(biāo)開(kāi)發(fā)或臨床數(shù)據(jù)倉(cāng)庫(kù)建設(shè)的工程師。2. 衛(wèi)寧電子病歷表結(jié)構(gòu)的組織邏輯從文檔到數(shù)據(jù)模型2.1 先分清三類(lèi)表主表、明細(xì)表、字典表拿到衛(wèi)寧電子病歷表結(jié)構(gòu)文檔不要從頭到尾逐行讀。我一般先按表名后綴和字段特征把它分成三類(lèi)這個(gè)分類(lèi)直接決定后面怎么寫(xiě) JOIN。第一類(lèi)是主表通常以PATIENT、VISIT、EMR開(kāi)頭或包含MASTER、RECORD字樣存放一次就診或一份病歷的核心標(biāo)識(shí)。第二類(lèi)是明細(xì)表表名里常帶DETAIL、ITEM、ENTRY一條主記錄對(duì)應(yīng)多條明細(xì)比如醫(yī)囑明細(xì)、檢驗(yàn)項(xiàng)目明細(xì)。第三類(lèi)是字典表表名多含DICT、CODE、TYPE用來(lái)做編碼翻譯比如性別代碼、科室代碼、診斷編碼。為什么先做這個(gè)分類(lèi)因?yàn)樾l(wèi)寧的表結(jié)構(gòu)文檔通常按模塊排列但實(shí)際查詢時(shí)你需要跨模塊 JOIN。如果不先分清主從關(guān)系很容易寫(xiě)出笛卡爾積。一個(gè)典型場(chǎng)景查某個(gè)患者某次住院的所有檢驗(yàn)結(jié)果你需要從就診主表拿到VISIT_ID再去檢驗(yàn)明細(xì)表按VISIT_ID過(guò)濾最后 JOIN 字典表翻譯檢驗(yàn)項(xiàng)目名稱(chēng)。三步走缺一步結(jié)果就不完整。提示文檔里如果看到XX_ID同時(shí)出現(xiàn)在兩張表里大概率是外鍵關(guān)聯(lián)字段優(yōu)先記下來(lái)。2.2 關(guān)鍵字段的命名規(guī)律與含義衛(wèi)寧電子病歷表結(jié)構(gòu)里字段命名有比較固定的套路。掌握這些規(guī)律你甚至可以在沒(méi)有文檔的情況下猜出七八成。PATIENT_ID是患者主索引通常全院唯一但注意有些老版本用PAT_NO或MRN。VISIT_ID是就診流水號(hào)一次住院或一次門(mén)診對(duì)應(yīng)一個(gè)這是最常用的關(guān)聯(lián)鍵。VISIT_TYPE區(qū)分門(mén)診、急診、住院值通常是1、2、3或O、E、I具體看文檔里的字典說(shuō)明。EMR_ID是電子病歷文檔主鍵一份病歷可能對(duì)應(yīng)多個(gè)EMR_ID比如入院記錄、病程記錄、手術(shù)記錄各一個(gè)。時(shí)間字段要特別留意。CREATE_TIME是記錄創(chuàng)建時(shí)間UPDATE_TIME是最后修改時(shí)間但衛(wèi)寧有些表用RECORD_TIME表示臨床發(fā)生時(shí)間和系統(tǒng)時(shí)間不是一回事。做質(zhì)控指標(biāo)時(shí)比如「入院記錄 24 小時(shí)內(nèi)完成」你要用的是臨床時(shí)間字段不是系統(tǒng)創(chuàng)建時(shí)間。這個(gè)坑我見(jiàn)過(guò)不止一次查出來(lái)的數(shù)據(jù)對(duì)不上最后發(fā)現(xiàn)是時(shí)間字段選錯(cuò)了。2.3 從文檔到 ER 圖手工梳理表關(guān)系的步驟文檔不會(huì)直接給你 ER 圖但你可以自己畫(huà)。步驟不復(fù)雜關(guān)鍵是耐心。第一步把文檔里所有表名抄到一張紙上或 Excel 里按模塊分組。第二步逐表標(biāo)注主鍵字段通常文檔里會(huì)標(biāo)PK或加粗。第三步找外鍵如果 A 表的某個(gè)字段和 B 表的主鍵同名或明顯相關(guān)畫(huà)一條線。第四步標(biāo)注關(guān)系類(lèi)型一對(duì)多、多對(duì)多、一對(duì)一。這個(gè)過(guò)程聽(tīng)起來(lái)笨但比直接上手寫(xiě) SQL 靠譜。我一般會(huì)重點(diǎn)梳理三條鏈路患者-就診-病歷、就診-醫(yī)囑-醫(yī)囑明細(xì)、就診-檢驗(yàn)-檢驗(yàn)結(jié)果。這三條鏈路覆蓋了電子病歷數(shù)據(jù)抽取 80% 的需求。梳理完之后你會(huì)得到一張自己的 ER 圖后面寫(xiě)查詢就是按圖索驥。3. 從表結(jié)構(gòu)文檔到可執(zhí)行 SQL查詢與抽取實(shí)戰(zhàn)3.1 用 VISIT_ID 串聯(lián)就診與病歷的最小查詢假設(shè)你要查某個(gè)患者最近一次住院的入院記錄內(nèi)容。文檔里告訴你就診信息在PAT_VISIT表病歷主表在EMR_DOCUMENT病歷內(nèi)容在EMR_CONTENT。下面是最小可用查詢-- 查詢指定患者最近一次住院的入院記錄 SELECT v.VISIT_ID, v.VISIT_TYPE, v.ADMISSION_TIME, d.EMR_ID, d.DOC_TYPE, -- 文檔類(lèi)型入院記錄通常為 ADMISSION_NOTE c.CONTENT_TEXT -- 病歷正文可能是 CLOB 或 TEXT 類(lèi)型 FROM PAT_VISIT v JOIN EMR_DOCUMENT d ON v.VISIT_ID d.VISIT_ID JOIN EMR_CONTENT c ON d.EMR_ID c.EMR_ID WHERE v.PATIENT_ID 你的患者ID AND v.VISIT_TYPE I -- I 表示住院 AND d.DOC_TYPE ADMISSION_NOTE ORDER BY v.ADMISSION_TIME DESC FETCH FIRST 1 ROW ONLY; -- 不同數(shù)據(jù)庫(kù)寫(xiě)法不同Oracle 用 ROWNUM這段 SQL 的邏輯很直接先從就診表按患者和就診類(lèi)型過(guò)濾拿到住院記錄再關(guān)聯(lián)病歷文檔表按文檔類(lèi)型篩出入院記錄最后關(guān)聯(lián)內(nèi)容表取正文。參數(shù)方面VISIT_TYPE的值一定要查文檔里的字典表確認(rèn)不同醫(yī)院實(shí)施時(shí)可能配成1或I。DOC_TYPE同理有的環(huán)境用中文編碼有的用英文縮寫(xiě)。FETCH FIRST是標(biāo)準(zhǔn) SQL 寫(xiě)法Oracle 老版本要用WHERE ROWNUM 1SQL Server 用TOP 1。注意EMR_CONTENT表可能很大正文是 CLOB 字段查詢時(shí)不要SELECT *只取需要的列。3.2 醫(yī)囑明細(xì)的層級(jí)展開(kāi)與過(guò)濾條件醫(yī)囑數(shù)據(jù)是電子病歷里結(jié)構(gòu)最復(fù)雜的部分之一。衛(wèi)寧的表結(jié)構(gòu)通常把醫(yī)囑拆成三層醫(yī)囑主表ORDERS、醫(yī)囑明細(xì)表ORDER_ITEMS、醫(yī)囑執(zhí)行表ORDER_EXECUTE。主表存醫(yī)囑的開(kāi)立時(shí)間、開(kāi)立醫(yī)生、醫(yī)囑類(lèi)型明細(xì)表存具體的藥品或項(xiàng)目執(zhí)行表存每次執(zhí)行的時(shí)間和執(zhí)行人。查一個(gè)患者住院期間的所有長(zhǎng)期醫(yī)囑SQL 大概長(zhǎng)這樣-- 查詢住院期間的長(zhǎng)期醫(yī)囑及明細(xì) SELECT o.ORDER_ID, o.ORDER_TYPE, -- 長(zhǎng)期/臨時(shí)文檔里查字典 o.START_TIME, o.DOCTOR_NAME, i.ITEM_NAME, i.DOSAGE, i.FREQUENCY FROM ORDERS o JOIN ORDER_ITEMS i ON o.ORDER_ID i.ORDER_ID WHERE o.VISIT_ID 目標(biāo)就診號(hào) AND o.ORDER_TYPE LONG -- 長(zhǎng)期醫(yī)囑具體值查字典 AND o.STATUS ACTIVE -- 有效醫(yī)囑避免已停止的 ORDER BY o.START_TIME;這里的關(guān)鍵參數(shù)是ORDER_TYPE和STATUS。ORDER_TYPE在不同版本里可能是0/1、L/T或長(zhǎng)期/臨時(shí)必須查文檔字典。STATUS字段用來(lái)過(guò)濾已停止或已作廢的醫(yī)囑如果不加這個(gè)條件你會(huì)把歷史停囑也查出來(lái)導(dǎo)致統(tǒng)計(jì)偏差。ORDER_ITEMS表里ITEM_NAME可能是編碼需要再 JOIN 藥品字典或項(xiàng)目字典翻譯成名稱(chēng)。3.3 檢驗(yàn)結(jié)果與病歷文本的關(guān)聯(lián)查詢質(zhì)控和科研場(chǎng)景經(jīng)常需要把檢驗(yàn)結(jié)果和病歷文本關(guān)聯(lián)起來(lái)比如查某個(gè)患者血糖異常時(shí)對(duì)應(yīng)的病程記錄。衛(wèi)寧的表結(jié)構(gòu)里檢驗(yàn)主表通常是LAB_TEST結(jié)果明細(xì)在LAB_RESULT病歷文本在EMR_CONTENT。關(guān)聯(lián)鍵是VISIT_ID加時(shí)間范圍。-- 查詢血糖異常前后 24 小時(shí)內(nèi)的病程記錄 SELECT l.TEST_NAME, l.RESULT_VALUE, l.REPORT_TIME, e.DOC_TYPE, e.CREATE_TIME, c.CONTENT_TEXT FROM LAB_TEST l JOIN LAB_RESULT r ON l.TEST_ID r.TEST_ID JOIN EMR_DOCUMENT e ON l.VISIT_ID e.VISIT_ID JOIN EMR_CONTENT c ON e.EMR_ID c.EMR_ID WHERE l.VISIT_ID 目標(biāo)就診號(hào) AND l.TEST_NAME LIKE %血糖% AND r.RESULT_VALUE 11.1 AND e.CREATE_TIME BETWEEN l.REPORT_TIME - INTERVAL 24 HOUR AND l.REPORT_TIME INTERVAL 24 HOUR AND e.DOC_TYPE PROGRESS_NOTE ORDER BY l.REPORT_TIME, e.CREATE_TIME;這段查詢的難點(diǎn)在時(shí)間范圍關(guān)聯(lián)。INTERVAL是 PostgreSQL 和 Oracle 的寫(xiě)法MySQL 用DATE_SUB和DATE_ADD。另外LAB_TEST和LAB_RESULT可能是一對(duì)多一個(gè)檢驗(yàn)項(xiàng)目多條結(jié)果JOIN 之后要注意去重。EMR_DOCUMENT和EMR_CONTENT也可能一對(duì)多如果一份病歷有多個(gè)版本需要按CREATE_TIME取最新版本。提示跨表時(shí)間關(guān)聯(lián)時(shí)先確認(rèn)所有時(shí)間字段的時(shí)區(qū)和精度衛(wèi)寧有些表存的是DATE有些是TIMESTAMP混用會(huì)丟精度。4. 衛(wèi)寧電子病歷表結(jié)構(gòu)對(duì)接的避坑與排查4.1 字段值不統(tǒng)一同一含義在不同表里編碼不同現(xiàn)象寫(xiě)好的查詢?cè)?A 醫(yī)院跑得通到 B 醫(yī)院結(jié)果為空。原因衛(wèi)寧不同項(xiàng)目實(shí)施時(shí)字典編碼可能被本地化修改。比如性別字段有的環(huán)境存1/2有的存M/F有的存男/女。解決不要硬編碼值先查DICT或CODE類(lèi)字典表或者從文檔的「值域說(shuō)明」章節(jié)確認(rèn)。我一般會(huì)寫(xiě)一個(gè)字典查詢子查詢把編碼翻譯成統(tǒng)一值再過(guò)濾。4.2 大表查詢超時(shí)EMR_CONTENT 和 LAB_RESULT 的索引陷阱現(xiàn)象查詢病歷正文或檢驗(yàn)結(jié)果時(shí)SQL 跑幾分鐘不出結(jié)果。原因EMR_CONTENT和LAB_RESULT是典型的大表幾百萬(wàn)甚至上千萬(wàn)行如果VISIT_ID或EMR_ID上沒(méi)有索引全表掃描必然超時(shí)。解決先確認(rèn)文檔里標(biāo)注的索引字段查詢時(shí)務(wù)必帶上索引列作為過(guò)濾條件。如果文檔沒(méi)標(biāo)用EXPLAIN看執(zhí)行計(jì)劃必要時(shí)讓 DBA 加索引。另外CLOB 字段不要放在WHERE里做LIKE性能極差。4.3 時(shí)間字段混用CREATE_TIME 和臨床時(shí)間的區(qū)別現(xiàn)象統(tǒng)計(jì)「入院記錄 24 小時(shí)內(nèi)完成率」時(shí)數(shù)據(jù)對(duì)不上。原因用了CREATE_TIME而不是臨床記錄時(shí)間。衛(wèi)寧有些表的CREATE_TIME是系統(tǒng)寫(xiě)入時(shí)間可能比實(shí)際書(shū)寫(xiě)時(shí)間晚幾小時(shí)甚至幾天。解決查文檔里有沒(méi)有RECORD_TIME、WRITE_TIME、CLINICAL_TIME這類(lèi)字段優(yōu)先用臨床時(shí)間。如果文檔沒(méi)寫(xiě)清楚找實(shí)施人員確認(rèn)或者對(duì)比幾條已知數(shù)據(jù)反推。4.4 關(guān)聯(lián)字段類(lèi)型不一致隱式轉(zhuǎn)換導(dǎo)致索引失效現(xiàn)象JOIN 查詢很慢但單獨(dú)查兩張表都很快。原因關(guān)聯(lián)字段類(lèi)型不一致比如 A 表VISIT_ID是VARCHAR2B 表是NUMBER數(shù)據(jù)庫(kù)做隱式轉(zhuǎn)換索引失效。解決查文檔確認(rèn)字段類(lèi)型寫(xiě) JOIN 時(shí)顯式轉(zhuǎn)換比如ON a.VISIT_ID TO_CHAR(b.VISIT_ID)。但更好的做法是讓 DBA 統(tǒng)一類(lèi)型或者建函數(shù)索引。4.5 文檔版本與數(shù)據(jù)庫(kù)不一致字段已廢棄或新增現(xiàn)象按文檔寫(xiě)的字段數(shù)據(jù)庫(kù)里報(bào)「無(wú)效標(biāo)識(shí)符」。原因文檔版本落后于實(shí)際數(shù)據(jù)庫(kù)或者醫(yī)院做了定制化修改。解決先用DESC 表名或查詢USER_TAB_COLUMNS確認(rèn)實(shí)際字段再對(duì)照文檔。如果發(fā)現(xiàn)文檔沒(méi)有的字段不要貿(mào)然使用先找實(shí)施確認(rèn)含義。我一般會(huì)維護(hù)一份「文檔 vs 實(shí)際」的差異表每次對(duì)接新醫(yī)院先跑一遍字段比對(duì)。5. 把表結(jié)構(gòu)文檔變成可復(fù)用的數(shù)據(jù)資產(chǎn)5.1 建立自己的元數(shù)據(jù)表字段映射與血緣記錄文檔是死的數(shù)據(jù)庫(kù)是活的。我習(xí)慣在對(duì)接完一家醫(yī)院后把關(guān)鍵表的字段映射、字典值、關(guān)聯(lián)關(guān)系整理成一張?jiān)獢?shù)據(jù)表存在自己的數(shù)據(jù)庫(kù)里。表結(jié)構(gòu)大概這樣CREATE TABLE MY_META_FIELD_MAP ( SOURCE_TABLE VARCHAR(100), -- 源表名 SOURCE_FIELD VARCHAR(100), -- 源字段 TARGET_TABLE VARCHAR(100), -- 目標(biāo)表名 TARGET_FIELD VARCHAR(100), -- 目標(biāo)字段 TRANSFORM_RULE VARCHAR(500), -- 轉(zhuǎn)換規(guī)則如字典翻譯 REMARK VARCHAR(500) -- 備注如版本差異 );這張表的好處是下次對(duì)接同版本衛(wèi)寧系統(tǒng)時(shí)直接查映射關(guān)系不用再翻文檔。TRANSFORM_RULE字段記錄字典翻譯邏輯比如SEX: 1-男, 2-女。REMARK記錄版本差異比如「V5.0 用 VISIT_IDV6.0 改用 ENCOUNTER_ID」。這個(gè)習(xí)慣幫我省了大量重復(fù)勞動(dòng)。5.2 用視圖封裝復(fù)雜關(guān)聯(lián)讓業(yè)務(wù)查詢不再碰底層表底層表結(jié)構(gòu)復(fù)雜業(yè)務(wù)人員或分析師直接查容易出錯(cuò)。我一般會(huì)建幾個(gè)核心視圖把常用的關(guān)聯(lián)和字典翻譯封裝進(jìn)去。比如CREATE VIEW V_PATIENT_VISIT_EMR AS SELECT v.PATIENT_ID, v.VISIT_ID, v.VISIT_TYPE, v.ADMISSION_TIME, v.DISCHARGE_TIME, d.EMR_ID, d.DOC_TYPE, c.CONTENT_TEXT FROM PAT_VISIT v LEFT JOIN EMR_DOCUMENT d ON v.VISIT_ID d.VISIT_ID LEFT JOIN EMR_CONTENT c ON d.EMR_ID c.EMR_ID;視圖的好處是屏蔽底層復(fù)雜性業(yè)務(wù)查詢只需要SELECT * FROM V_PATIENT_VISIT_EMR WHERE PATIENT_ID xxx。但要注意視圖里的LEFT JOIN可能帶來(lái)性能問(wèn)題如果底層表很大建議加物化視圖或定時(shí)刷新。另外視圖不要嵌套太深否則排查問(wèn)題很痛苦。5.3 驗(yàn)證方法用已知病例反查數(shù)據(jù)完整性做完對(duì)接后怎么驗(yàn)證查出來(lái)的數(shù)據(jù)是對(duì)的我的習(xí)慣是找?guī)讉€(gè)已知病例手工核對(duì)。具體做法選一個(gè)住院患者從 HIS 系統(tǒng)里導(dǎo)出他的入院記錄、病程記錄、檢驗(yàn)報(bào)告然后用自己的查詢跑一遍對(duì)比字段值和內(nèi)容。重點(diǎn)核對(duì)三類(lèi)數(shù)據(jù)時(shí)間字段是否一致、字典翻譯是否正確、明細(xì)記錄是否漏查。如果發(fā)現(xiàn)差異先查是不是過(guò)濾條件太嚴(yán)再查是不是 JOIN 丟了記錄。我遇到過(guò)LEFT JOIN寫(xiě)成INNER JOIN導(dǎo)致沒(méi)有檢驗(yàn)記錄的患者被過(guò)濾掉的情況這種錯(cuò)誤在統(tǒng)計(jì)總體指標(biāo)時(shí)影響很大。驗(yàn)證通過(guò)后把查詢固化下來(lái)作為后續(xù)開(kāi)發(fā)的基準(zhǔn)。5.4 一個(gè)具體技巧用文檔目錄反推模塊優(yōu)先級(jí)衛(wèi)寧電子病歷表結(jié)構(gòu)文檔通常有目錄目錄順序往往反映了模塊的重要性或使用頻率。我一般會(huì)先看目錄里哪些模塊被放在前面比如「患者基本信息」「就診信息」「病歷文檔」通常在前這些就是核心表優(yōu)先梳理。后面的「質(zhì)控」「科研」「接口」模塊按需處理。另外文檔里的「修訂記錄」或「版本說(shuō)明」頁(yè)很關(guān)鍵它會(huì)告訴你哪些表在哪個(gè)版本新增或廢棄。如果對(duì)接的是老版本系統(tǒng)直接跳過(guò)新增表省時(shí)間。如果文檔沒(méi)有修訂記錄就對(duì)比數(shù)據(jù)庫(kù)實(shí)際表清單差異部分重點(diǎn)確認(rèn)。提示文檔里的示例 SQL 或查詢片段不要直接抄往往和實(shí)際環(huán)境有出入只作參考。這些年做衛(wèi)寧電子病歷對(duì)接最大的教訓(xùn)就是別信文檔的「完整性」。文檔寫(xiě)的是標(biāo)準(zhǔn)版醫(yī)院跑的是定制版中間差著無(wú)數(shù)實(shí)施細(xì)節(jié)。我現(xiàn)在的習(xí)慣是拿到文檔先跑一遍字段比對(duì)再找實(shí)施確認(rèn)字典值最后用真實(shí)病例驗(yàn)證。三步走完后面寫(xiě)查詢才踏實(shí)。希望幫到你。本文還有配套的精品資源點(diǎn)擊獲取