Files
pharmacy-stats-api/PMPLUS20_MIGRATION_GUIDE.md
root 75559a78f9 docs: PRICE_N vs REAL_PRICE 매핑 상세 분석 추가
- 일반 환자: REAL_PRICE = PRICE_N 정확히 일치 확인
- 특수 보험 환자 (차상위/선별급여):
  - 지성윤(차상위2): 상한제초과분(EXP_UNDER_EXE_PRICE) 포함
  - 임해자(선별급여): 선별급여80%(SE_PRICE_P_80) 포함
- v1 PRICE_N 버그: 상한제초과/선별급여분 미포함
- v2 REAL_PRICE = 수납테이블(TBSIR000_01)의 RECP_AMT와 일치
- 결론: REAL_PRICE 매핑 유지 (v1보다 정확한 실제 결제금액)
2026-04-01 15:07:35 +00:00

10 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 매핑 상세 분석

결론: REAL_PRICE = 진짜 수납금액

PMPLUS20의 REAL_PRICE는 수납테이블(TBSIR000_01)의 RECP_AMT, SUNAB_PRICE와 정확히 일치함.

검증 케이스 (20260324)

환자 보험구분 v1 PRICE_N v2 REAL_PRICE v2 수납(RECP_AMT) 설명
박명순 건강보험+비급여 89,600 89,600 89,600 일반 케이스
김상훈 건강보험+비급여 70,900 70,900 70,900 일반 케이스
지성윤 차상위2(F) 500 11,920 11,920 특수 케이스 ⚠️
임해자 건강보험+선별급여 19,700 31,700 31,700 특수 케이스 ⚠️

일반 환자 (건강보험 + 비급여)

REAL_PRICE = EXE_PRICE(본인부담) + NON_DRUG_PRICE(비급여약) + EXP_EXE_PRICE(비급여조제)
         = PRICE_N (정확히 일치)

특수 보험 환자 (차상위/선별급여)

지성윤 (차상위2):

EXE_PRICE = 500 (기본 본인부담)
EXP_UNDER_EXE_PRICE = 11,420 (상한제초과 본인부담)
REAL_PRICE = 500 + 11,420 = 11,920 (진짜 수납액)
v1 PRICE_N = 500 ← 상한제초과분 누락!

임해자 (건강보험 + 선별급여 80%):

EXE_PRICE = 19,700 (기본 본인부담)
SE_PRICE_P_80 = 12,000 (선별급여 80% 본인부담)
REAL_PRICE = 19,700 + 12,000 = 31,700 (진짜 수납액)
v1 PRICE_N = 19,700 ← 선별급여분 누락!

v1 PRICE_N 버그 원인

PharmIT3000의 PRICE_N은 다음 항목을 미포함:

  • EXP_UNDER_EXE_PRICE: 상한제초과 본인부담
  • SE_PRICE_P_80/90/50: 선별급여 본인부담

PMPLUS20의 REAL_PRICE는 이 모두를 포함한 실제 결제금액이며, 수납테이블(TBSIR000_01)의 RECP_AMT와 일치함.

결론: 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)