# db_hospital
에이전트 매핑 테스트를 위한 병원 데이터

## Oracle schema draft
병원 데이터를 5개 업무영역으로 분리한 Oracle DDL 초안입니다.
현재 스크립트는 `ASIS` 데이터베이스를 가정해서, 거래 테이블에 환자명/부서명/의사명/코드명 등이 중복 저장되는 비정규화 구조로 작성했습니다.

- 공통: `scripts/oracle/01_common.sql`
- 일반: `scripts/oracle/02_general.sql`
- 원무: `scripts/oracle/03_administration.sql`
- 진료: `scripts/oracle/04_clinical.sql`
- 진료지원: `scripts/oracle/05_clinical_support.sql`
- 전체 실행: `scripts/oracle/00_all.sql`

## 실행 예시
SQL*Plus 또는 SQLcl에서 아래처럼 실행하면 됩니다.

```sql
@scripts/oracle/00_all.sql
```

## ASIS 대량 샘플 데이터
ASIS Oracle용 대량 데이터 생성 스크립트를 추가했습니다. 기본값은 수만~수십만 건 수준이며, 변수만 바꾸면 더 크게 늘릴 수 있습니다.

- 전체 적재: `scripts/oracle/10_seed_all.sql`
- 공통: `scripts/oracle/11_seed_common.sql`
- 일반: `scripts/oracle/12_seed_general.sql`
- 원무: `scripts/oracle/13_seed_administration.sql`
- 진료: `scripts/oracle/14_seed_clinical.sql`
- 진료지원: `scripts/oracle/15_seed_clinical_support.sql`

실행 예시:

```sql
@scripts/oracle/10_seed_all.sql
```

기본 설정 기준으로 원무 계산, 진료 처방, 진료지원 검사/영상/조제 데이터가 많이 들어가도록 되어 있습니다.

## PostgreSQL TOBE schema draft
`TOBE` 데이터베이스는 PostgreSQL 기준으로 정규화된 스키마를 별도로 작성했습니다.

- 공통: `scripts/postgresql/01_common.sql`
- 일반: `scripts/postgresql/02_general.sql`
- 원무: `scripts/postgresql/03_administration.sql`
- 진료: `scripts/postgresql/04_clinical.sql`
- 진료지원: `scripts/postgresql/05_clinical_support.sql`
- 전체 실행: `scripts/postgresql/00_all.sql`

## PostgreSQL 실행 예시
`psql`에서 아래처럼 실행하면 됩니다.

```sql
\i scripts/postgresql/00_all.sql
```

기존에 떠 있는 PostgreSQL 컨테이너 `pg-db`를 그대로 쓸 예정이라면, 이 스키마를 그 컨테이너에만 적용하면 됩니다.
현재 `pg-db`는 PostgreSQL 15이며, `ekis_user` superuser를 사용합니다. 먼저 TOBE 전용 DB/role을 만든 뒤 스키마와 seed를 적용합니다.

```bash
docker exec pg-db mkdir -p /tmp/db_hospital/scripts /tmp/db_hospital/docker/postgresql/init
docker cp scripts/postgresql pg-db:/tmp/db_hospital/scripts/
docker cp docker/postgresql/init/99_create_domain_users.sql pg-db:/tmp/db_hospital/docker/postgresql/init/
docker exec -w /tmp/db_hospital -i pg-db psql -U ekis_user -d ekis_web -f scripts/postgresql/18_create_hospital_tobe_db.sql
docker exec -w /tmp/db_hospital -i pg-db psql -U hospital_tobe -d hospital_tobe -f scripts/postgresql/00_all.sql
docker exec -w /tmp/db_hospital -i pg-db psql -U ekis_user -d hospital_tobe -f docker/postgresql/init/99_create_domain_users.sql
```

실제 `pg-db`의 DB명이나 사용자가 다르면 bootstrap 실행 시의 `-U`와 `-d`만 맞춰서 바꾸면 됩니다.

## PostgreSQL 메타 DB (agent_etl)
기존 `pg-db`에 메타 DB `agent_etl`을 추가로 생성해서 사용합니다.

- DB: `agent_etl`
- 스키마: `agent_etl` (DB 내부)
- 유저: `agent_etl_user` / 비번 `0119`
- 연결정보 테이블: `agent_etl.db_conn` (PK: `conn_name`)
- 환경변수: `AGENT_ETL_DATABASE_URL=postgresql://agent_etl_user:0119@db:5432/agent_etl`
- 생성/갱신 스크립트:
  - DB/유저 생성: `scripts/postgresql/19_create_agent_etl_db.sql`
  - 스키마/테이블/시드: `scripts/postgresql/20_agent_etl_meta.sql`

적용 예시:

```bash
docker exec -i pg-db psql -U ekis_user -d ekis_web < scripts/postgresql/19_create_agent_etl_db.sql
docker exec -i pg-db psql -U ekis_user -d agent_etl < scripts/postgresql/20_agent_etl_meta.sql
```

## MySQL DW / DM schema draft
`DW` 데이터베이스는 MySQL 기준으로 TOBE 스키마를 받아 적재하는 분석용 모델로 작성했습니다.

- 차원: `scripts/mysql/01_dim.sql`
- 팩트: `scripts/mysql/02_fact.sql`
- DM: `scripts/mysql/03_dm.sql`
- TOBE 스테이징: `scripts/mysql/10_staging.sql`
- 차원 적재 ETL: `scripts/mysql/11_etl_dim.sql`
- 팩트 적재 ETL: `scripts/mysql/12_etl_fact.sql`
- DM 집계 ETL: `scripts/mysql/13_etl_dm.sql`
- 전체 실행: `scripts/mysql/00_all.sql`

ERD 문서: `docs/mysql_erd.md`

MySQL은 PostgreSQL을 직접 읽지 않으므로, TOBE PostgreSQL 데이터를 먼저 `stg_tobe_*` 테이블에 적재한 뒤 아래 순서로 실행하면 됩니다.

```sql
SOURCE scripts/mysql/10_staging.sql;
SOURCE scripts/mysql/11_etl_dim.sql;
SOURCE scripts/mysql/12_etl_fact.sql;
SOURCE scripts/mysql/13_etl_dm.sql;
```

## Docker 구성
Oracle ASIS와 MySQL DW는 컨테이너로 올릴 수 있도록 아래 파일을 추가했습니다.
PostgreSQL TOBE는 기존에 떠 있는 `pg-db`를 재사용하는 방향으로 준비했습니다.

- Compose: `docker-compose.yml`
- Oracle init: `docker/oracle/init/00_init.sql`
- PostgreSQL init: `docker/postgresql/init/00_init.sql`
- MySQL init: `docker/mysql/init/00_init.sql`

기본 포트와 계정은 아래 기준입니다.

- Oracle: `1521`, 업무영역별 schema user 5개 (password 모두 `0119`)
  - 공통: `hsp_com`
  - 일반: `hsp_gen`
  - 원무: `hsp_adm`
  - 진료: `hsp_clinic`
  - 진료지원: `hsp_clinic_sup`
- PostgreSQL: 기존 `pg-db` 사용, 스키마만 적용
- MySQL: `3306`, db `hospital_dw`, user `dw_user`, password `0119`, root password `root`

Oracle 컨테이너 안의 SQL*Plus로 SYS 계정 접속이 필요하면 아래 명령을 사용합니다.

```bash
docker exec -it etlers-db-oracle sqlplus sys/oracle@//localhost:1521/FREEPDB1 as sysdba
```

CDB 루트로 접속하려면 서비스명을 `FREE`로 바꿉니다.

```bash
docker exec -it etlers-db-oracle sqlplus sys/oracle@//localhost:1521/FREE as sysdba
```

Oracle/MySQL 데이터 디렉터리는 USB 경로로 바인드 마운트하도록 구성했습니다.

- 설정 파일: `.env.example` (필요하면 `.env`로 복사해서 사용)
- 필요한 환경변수: `DBH_USB_ROOT` (예: `/Users/etlers/Volumes/etlers_usb/db_hospital`)

USB 아래에 디렉터리를 미리 만들어 둔 뒤 실행하면 됩니다.

```bash
mkdir -p ~/Volumes/etlers_usb/db_hospital/oracle/oradata
mkdir -p ~/Volumes/etlers_usb/db_hospital/mysql/data
cp .env.example .env
docker compose up -d oracle-asis mysql-dw
```

PostgreSQL TOBE는 별도 컨테이너를 띄우지 않고 기존 `pg-db` 안의 `hospital_tobe` DB로 관리합니다.

## ERD
- ASIS 전체 ERD: `docs/oracle_erd.md`
- TOBE 전체 ERD: `docs/postgresql_erd.md`
- DW/DM ERD: `docs/mysql_erd.md`
- ASIS 공통 ERD: `docs/asis_erd_common.md`
- ASIS 일반 ERD: `docs/asis_erd_general.md`
- ASIS 원무 ERD: `docs/asis_erd_administration.md`
- ASIS 진료 ERD: `docs/asis_erd_clinical.md`
- ASIS 진료지원 ERD: `docs/asis_erd_clinical_support.md`
- TOBE 공통 ERD: `docs/tobe_erd_common.md`
- TOBE 일반 ERD: `docs/tobe_erd_general.md`
- TOBE 원무 ERD: `docs/tobe_erd_administration.md`
- TOBE 진료 ERD: `docs/tobe_erd_clinical.md`
- TOBE 진료지원 ERD: `docs/tobe_erd_clinical_support.md`

## 업무영역 개요
- 공통: 코드, 부서, 직원, 환자, 보험, 병실 같은 기준정보
- 일반: 예약, 접수/체크인, 대기열, 환자 안내
- 원무: 내원/입원, 수가 청구, 수납, 보험청구
- 진료: 바이탈, 진료기록, 진단, 처방/처치오더
- 진료지원: 검체, 검사, 영상, 조제

## ASIS 모델링 방향
- 마스터 참조키를 최소화하고 업무 테이블에 스냅샷 컬럼을 함께 저장
- 코드값과 코드명을 같이 보관해서 TOBE 정규화 매핑 대상으로 활용
- 업무영역 간 연결은 `id` 뿐 아니라 `*_no`, 명칭 컬럼도 남겨 레거시 데이터 느낌을 유지

## TOBE 모델링 방향
- 공통 마스터와 코드 체계를 기준으로 업무 테이블이 외래키로 연결
- 중복 명칭 컬럼 대신 식별자 중심으로 설계
- 검사, 영상, 처방, 수납 같은 거래 데이터는 카탈로그와 실적 테이블을 분리
- Oracle ASIS와 차이를 크게 두기 위해 PostgreSQL은 약어 기반 네이밍(`tb_cd`, `tb_pt`, `tb_enc`, `*_cd`, `*_nm`)을 사용
