Files
pharmacy-stats-api/PMPLUS20_MIGRATION_GUIDE.md
root d6a1484b54 docs: 보험구분 매핑 문서 업데이트 - 전체 보험종류 포함
- 3-2절: MPRE_TYPE + MPRE_TYPE_GUBUN 조합 매핑 추가
  - 건강보험(0), 의료급여1종(1), 산재(2), 의료급여2종(3)
  - 차상위1(7←4+C), 보훈(E←4+E), 차상위2(F←4+F), 비급여(9)
- 4절: v2 쿼리에 정확한 CASE문 반영
- 5절: 2026년 3월 전체 검증 결과로 업데이트 (V1=V2 일치 확인)
- 6절: 작업 이력으로 변경, 완료된 항목 체크
2026-04-01 14:57:56 +00:00

9.2 KiB

PMPLUS20 테이블 매핑 가이드 (pharmacy-stats-api v2)

1. DB 연결 정보

구분 서버 DB SA 비밀번호
v1 PharmIT3000 192.168.0.201\PM2014 PM_PRES tmddls214!%(
v2 PMPLUS20 192.168.0.201\PMPLUS20 PM_MAIN newpro2020!@

IP는 반드시 192.168.0.201 고정 (두 인스턴스 SA 비밀번호 다름)


2. 테이블 매핑 (확정)

처방 조제 통계 (pharmacy-stats-api용)

역할 v1 (PharmIT3000) v2 (PMPLUS20) 검증
처방 헤더 PM_PRES..PS_MAIN PM_MAIN..TBSID040_03 확정
수납/결제 PM_PRES..CD_SUNAB PM_MAIN..TBSIR000_01 확정

JOIN 관계

-- v1
FROM PM_PRES..PS_MAIN m
LEFT JOIN PM_PRES..CD_SUNAB n ON n.PRESERIAL = m.PreSerial

-- v2
FROM PM_MAIN..TBSID040_03 m
LEFT JOIN PM_MAIN..TBSIR000_01 n ON n.DRUG_SEQ = m.DRUG_SEQ

참고: OTC 판매 매핑 (person-lookup-web-local용, 별도)

역할 v1 v2
OTC 판매 헤더 SALE_MAIN TBSIM040_28
OTC 판매 상세 SALE_SUB TBSIM040_29
OTC 결제 수납 CD_SUNAB TBSIR000_01

3. 컬럼 매핑 (확정)

3-1. 처방 헤더 (PS_MAIN → TBSID040_03)

v1 컬럼 v2 컬럼 역할 검증 금액 (20260324) 상태
PreSerial DRUG_SEQ 처방 일련번호 20260324000004 = 동일
INDATE SUNAB_DT 조제일자 (YYYYMMDD) 동일
PRICE_T TOT_PRICE 보험 약제비 총액 9,476,000 = 동일
PRICE_C INS_PRICE 청구금액 7,068,800 = 동일
PRICE_P EXE_PRICE 본인부담금 2,407,200 = 동일
PRICE_N REAL_PRICE 수납금액 2,838,420 (차이 23,420원 — 아래 참고)
S_Prep INS_PREP_PRICE 조제료 2,277,850 = 동일
Drug_T4 NON_DRUG_PRICE + EXP_EXE_PRICE 비급여 약제비 292,140+120,420=412,560
PaNum PAT_JUMIN_NO 주민번호 (연령 계산) 동일
PaName PAT_NM 환자명 동일
OrderName YOYANG_NM 처방 병원명 동일

3-2. 보험구분 (PreGubun → MPRE_TYPE + MPRE_TYPE_GUBUN)

v2에서 MPRE_TYPE='4'는 특수보험 그룹이며, MPRE_TYPE_GUBUN으로 세부 구분함.

v1 PreGubun v2 MPRE_TYPE v2 MPRE_TYPE_GUBUN 의미 건수 (202603)
'0' '0' '0' 건강보험 3,325건
'1' '1' '0' 의료급여1종 259건
'2' '2' '0' 산재 17건
'3' '3' '0' 의료급여2종 6건
'7' '4' 'C' 차상위1 7건
'E' '4' 'E' 보훈 32건
'F' '4' 'F' 차상위2 11건
'9' '9' '0' 비급여 34건

v2에서 PreGubun 변환 SQL:

CASE
    WHEN m.MPRE_TYPE = '4' AND m.MPRE_TYPE_GUBUN = 'E' THEN 'E'  -- 보훈
    WHEN m.MPRE_TYPE = '4' AND m.MPRE_TYPE_GUBUN = 'F' THEN 'F'  -- 차상위2
    WHEN m.MPRE_TYPE = '4' AND m.MPRE_TYPE_GUBUN = 'C' THEN '7'  -- 차상위1
    ELSE ISNULL(m.MPRE_TYPE, '0')
END AS PreGubun

주의: MPRE_TYPE이 기본 보험구분. PRES_GUBUN은 다른 용도 (A/E 값)

v2 전용 필터: PRES_GUBUN = 'E'인 "재고보정" 레코드는 제외해야 함 (DRUG_SEQ='20260324099999' 형태, v1에는 없음)

3-3. 시간가산 (Holiday → HD_ADD + PRES_TIME_GUBUN)

v1의 Holiday는 단일 컬럼, v2는 두 컬럼 조합:

v2 HD_ADD v2 PRES_TIME_GUBUN v1 Holiday 의미
'1' '0' '1' 일반
'2' '0' '2' 공휴일 가산
'1' '1' '3' 시간외 가산
'2' '1' '4' 공휴+시간외

v2에서 Holiday 계산 공식:

# PMPLUS20 → PharmIT3000 Holiday 변환
if hd_add == '2' and time_gubun == '1':
    holiday = '4'  # 공휴+시간외
elif hd_add == '2':
    holiday = '2'  # 공휴
elif time_gubun == '1':
    holiday = '3'  # 시간외
else:
    holiday = '1'  # 일반

3-4. 수납/결제 (CD_SUNAB → TBSIR000_01)

v1 컬럼 v2 컬럼 역할 상태
CD_SUNAB.PRESERIAL TBSIR000_01.DRUG_SEQ JOIN 키
CD_SUNAB.Appr_Gubun TBSIR000_01.APPR_GUBUN 결제수단 구분 값 동일
CD_SUNAB.nAPPROVAL_NUM TBSIR000_01.CARD_ADM_NO 승인번호

결제 구분 값 분포 (20260324):

  • '9': 179건 (카드)
  • 'A': 24건
  • '0': 5건
  • '2': 3건 (현금)

4. v2 쿼리 (변환 완료)

SELECT
    m.DRUG_SEQ       AS PreSerial,
    -- 보험구분 변환: MPRE_TYPE + MPRE_TYPE_GUBUN → PreGubun
    CASE
        WHEN m.MPRE_TYPE = '4' AND m.MPRE_TYPE_GUBUN = 'E' THEN 'E'  -- 보훈
        WHEN m.MPRE_TYPE = '4' AND m.MPRE_TYPE_GUBUN = 'F' THEN 'F'  -- 차상위2
        WHEN m.MPRE_TYPE = '4' AND m.MPRE_TYPE_GUBUN = 'C' THEN '7'  -- 차상위1
        ELSE ISNULL(m.MPRE_TYPE, '0')
    END AS PreGubun,
    m.PAT_JUMIN_NO   AS PaNum,
    m.YOYANG_NM      AS OrderName,
    -- Holiday 변환: HD_ADD + PRES_TIME_GUBUN → Holiday
    CASE 
        WHEN m.HD_ADD = '2' AND m.PRES_TIME_GUBUN = '1' THEN '4'
        WHEN m.HD_ADD = '2' THEN '2'
        WHEN m.PRES_TIME_GUBUN = '1' THEN '3'
        ELSE '1'
    END AS Holiday,
    m.TOT_PRICE      AS PRICE_T,
    (ISNULL(m.NON_DRUG_PRICE, 0) + ISNULL(m.EXP_EXE_PRICE, 0)) AS Drug_T4,
    m.INS_PREP_PRICE AS S_Prep,
    m.INS_PRICE      AS PRICE_C,
    m.EXE_PRICE      AS PRICE_P,
    m.REAL_PRICE      AS PRICE_N,
    ISNULL(n.APPR_GUBUN, '') AS Appr_Gubun,
    ISNULL(n.CARD_ADM_NO, '') AS nAPPROVAL_NUM
FROM PM_MAIN..TBSID040_03 m
LEFT JOIN PM_MAIN..TBSIR000_01 n ON n.DRUG_SEQ = m.DRUG_SEQ
WHERE m.SUNAB_DT BETWEEN ? AND ?
  AND m.PRES_GUBUN != 'E'   -- 재고보정 레코드 제외

5. 데이터 검증 결과 (20260324)

건수

항목 v1 v2 비고
전체 건수 211건 212건 v2에 "재고보정" 1건 추가 (PRES_GUBUN='E' 필터로 해결)
필터 후 211건 211건 일치

금액 합계

항목 v1 v2 일치
PRICE_T (보험약제비) 9,476,000 9,476,000
PRICE_C (청구금액) 7,068,800 7,068,800
PRICE_P (본인부담금) 2,407,200 2,407,200
S_Prep (조제료) 2,277,850 2,277,850
Drug_T4 (비급여약제비) 412,560 412,560 (NON_DRUG+EXP_EXE)
PRICE_N (수납금액) 2,815,000 2,838,420 ⚠️ 차이 23,420원 (아래 설명)

PRICE_N vs REAL_PRICE 차이 원인 (정상)

20260324 기준 2건에서 차이 발생:

환자 v1 PRICE_N v2 REAL_PRICE 차이 보험구분
지성윤 500 11,920 +11,420 차상위(F)
임해자 19,700 31,700 +12,000 -

원인: PharmIT3000은 차상위/의료급여 등 특수 보험에서 비급여 약제비를 PRICE_N에 미반영하는 버그가 있었음. PMPLUS20의 REAL_PRICE는 비급여 약제비를 포함한 실제 수납액으로 개선됨.

결론: v2(PMPLUS20)의 REAL_PRICE가 더 정확한 값. 차이는 시스템 개선에 의한 정상 차이.

보험구분별 (2026년 3월 전체 검증)

보험구분 v1 건수 v2 건수 일치
0 (건강보험) 3,359 3,359
1 (의료급여1종) 271 271
2 (산재) 17 17
3 (의료급여2종) 6 6
7 (차상위1) 8 8
9 (비급여) 35 35
E (보훈) 32 32
F (차상위2) 11 11

결제수단별

구분 v1 건수 v2 건수 일치
9 (카드) 179 179
A 24 24
0 5 5
2 (현금) 3 3

6. 작업 이력

  • 테이블 매핑 확정 (PS_MAIN → TBSID040_03)
  • 컬럼 매핑 확정 (13개 컬럼 전체)
  • 수납 테이블 매핑 확정 (CD_SUNAB → TBSIR000_01)
  • 변환 쿼리 작성
  • queries/v2_pmplus20.py 코드 수정 (2026-04-01)
  • 보험구분 매핑 완료 - 보훈/차상위1/차상위2 정확히 변환 (2026-04-01)
  • 2026년 3월 전체 기간 보험구분별 건수 검증 완료 (V1=V2 일치)
  • /api/compare로 UI 수치 검증
  • 시간별/결제별/병원별 세부 수치 검증

7. 참고: PMPLUS20 주요 테이블 구조 (210개 중 데이터 있는 것)

테이블 행수 추정 역할
TBSWH040_02 6,533,993 입고 이력 상세
TBSID040_05 1,543,564 조제 상세 (처방전 약품)
TBSID040_04 1,542,882 조제 상세 (원본)
TBSIR000_01 426,751 수납/결제 정보
TBSID040_03 394,802 처방 헤더 (= PS_MAIN)
TBSIM040_01 188,852 약품 마스터 (= CD_GOODS)
TBSIM040_29 49,161 OTC 판매 상세 (= SALE_SUB)
TBSIM040_28 28,813 OTC 판매 헤더 (= SALE_MAIN)