Files
pharmacy-stats-api/PMPLUS20_MIGRATION_GUIDE.md
root 8b4e8f7a0a feat: PMPLUS20(v2) 테이블 매핑 완료 및 쿼리 수정
- config.py: PMPLUS20 서버(192.168.0.201\PMPLUS20) 및 SA 비밀번호 수정
- v2_pmplus20.py: PS_MAIN→TBSID040_03, CD_SUNAB→TBSIR000_01 매핑 적용
  - 컬럼 매핑: PRICE_T→TOT_PRICE, PRICE_C→INS_PRICE, PRICE_P→EXE_PRICE 등
  - Drug_T4 = NON_DRUG_PRICE + EXP_EXE_PRICE
  - Holiday = HD_ADD + PRES_TIME_GUBUN 조합
  - PreGubun = MPRE_TYPE (차상위 F 별도 처리)
  - PRES_GUBUN='E' 재고보정 레코드 제외
- PMPLUS20_MIGRATION_GUIDE.md: 전체 매핑 가이드 문서 추가
- app.py: 포트 5060→5050 변경

20260324 기준 검증: 건수/금액/보험별/결제별 일치 확인
PRICE_N(수납) 2건 차이(23,420원)는 비급여 수납 처리 개선에 의한 정상 차이

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-04-01 14:45:31 +00:00

7.7 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)

v1 PreGubun v2 MPRE_TYPE 의미 건수 (20260324)
'0' '0' 건강보험 191건
'1' '1' 의료급여 16건
'9' '9' 비급여 2건
'F' MPRE_TYPE_GUBUN='F' 차상위 2건

주의: 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,
    m.MPRE_TYPE      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가 더 정확한 값. 차이는 시스템 개선에 의한 정상 차이.

보험구분별

보험구분 v1 건수 v2 건수 일치
0 (건강보험) 191 191
1 (의료급여) 16 16
9 (비급여) 2 2
F (차상위) 2 2

결제수단별

구분 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 코드 수정
  • /api/compare로 전체 기간 수치 검증
  • 보험별/시간별/결제별/병원별 세부 수치 검증

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)