V1 PharmIT3000 구조 분석: - PS_Main: 처방헤더 (PRICE_N만, 합산 안됨) - PS_Main_Sub: 처방 부가정보 (SE_PRICE_P_80 등 선별급여 컬럼 있음!) - CD_SUNAB: 수납 (ETC_CARD에 합산 결과 저장) V1 버그 원인: - 수납 화면에서는 PS_Main + PS_Main_Sub JOIN해서 계산 - CD_SUNAB.ETC_CARD에 정확히 저장 - 하지만 PS_Main.PRICE_N은 업데이트 안 함 SE_PRICE 컬럼 이력: - PS_Main_Sub 테이블: 2010년 초기 스키마에 생성 - SE_PRICE_P_* 컬럼: 선별급여 제도 시행 후 추가 - 실제 데이터: 2026년부터 6건 존재 V2 PMPLUS20 개선: - REAL_PRICE에 모든 항목 합산해서 저장 - 수납테이블 RECP_AMT와 일치 보장
12 KiB
12 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 스키마 분석: 선별급여/상한제 데이터는 어디에?
V1 PharmIT3000에도 데이터는 있다! PS_Main_Sub 테이블에 저장됨:
-- V1 PharmIT3000에서 선별급여/상한제 확인
SELECT
m.PreSerial, m.PRICE_N,
s.SE_PRICE_P_80, -- 선별급여 80% 본인부담
s.SE_PRICE_P, -- 선별급여 본인부담 합계
c.ETC_CARD -- 실제 수납액
FROM PS_Main m
JOIN PS_Main_Sub s ON s.PreSerial = m.PreSerial
JOIN CD_SUNAB c ON c.PRESERIAL = m.PreSerial
WHERE s.SE_PRICE_P > 0
V1 테이블 구조:
| 테이블 | 역할 | 선별급여/상한제 |
|---|---|---|
PS_Main |
처방 헤더 | ❌ PRICE_N만 (합산 안됨) |
PS_Main_Sub |
처방 부가정보 | ✅ SE_PRICE_P_80, SE_PRICE_P 등 |
CD_SUNAB |
수납 | ✅ ETC_CARD에 합산 결과 |
검증 케이스 (V1):
| 환자 | PS_Main.PRICE_N | PS_Main_Sub.SE_PRICE_P_80 | CD_SUNAB.ETC_CARD |
|---|---|---|---|
| 지성윤(차상위2) | 500 | 11,420 | 11,920 ✅ |
| 임해자(선별급여) | 19,700 | 12,000 | 31,700 ✅ |
문제점: PS_Main.PRICE_N이 PS_Main_Sub의 선별급여/상한제 금액을 합산하지 않음.
선별급여 컨럼 추가 이력
PS_Main_Sub테이블: 2010년 초기 스키마에 생성SE_PRICE_P_*커럼들: 나중에 추가됨 (선별급여 제도 시행 후)- 실제 데이터: 2026년부터 6건 존재 (최근 사용 시작)
V1 수납 프로세스 (추정)
- 수납 화면에서
PS_Main+PS_Main_SubJOIN해서 총액 계산 - 계산된 금액을
CD_SUNAB.ETC_CARD에 저장 - 하지만
PS_Main.PRICE_N은 업데이트 안 함 (버그)
V2 PMPLUS20 개선 사항
PMPLUS20은 이 문제를 해결:
TBSID040_03.REAL_PRICE에 모든 항목 합산해서 저장EXP_UNDER_EXE_PRICE,SE_PRICE_P_80등 별도 컨럼도 유지- 수납테이블(TBSIR000_01)의
RECP_AMT와 일치 보장
결론: REAL_PRICE 매핑 유지가 맞음. V1의 PRICE_N 버그를 V2에서 수정한 것.
보험구분별 (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) |