fix: 완전한 통합 DB 스키마 완성 - 모든 누락 테이블 추가
Some checks failed
SonarQube Analysis / SonarQube Scan (push) Has been cancelled
Some checks failed
SonarQube Analysis / SonarQube Scan (push) Has been cancelled
🗄️ 추가된 주요 테이블: - Jobs 테이블 (프로젝트 관리, project_type 포함) - 자재 규격/재질 기준표 (8개 테이블) - 자재 비교 시스템 (리비전 비교, 해시 기반) - Tubing 시스템 (5개 테이블 + 제조사 데이터) 📊 성능 최적화: - 복합 인덱스, GIN 인덱스, 조건부 인덱스 - 총 50+ 인덱스로 검색/정렬 성능 극대화 🔧 자동화 기능: - 해시 자동 생성 함수 및 트리거 - updated_at 자동 갱신 트리거 - 정규화된 description 자동 생성 📈 통계 및 뷰: - classification_summary (분류 통계) - classification_performance (분류 성능) - material_inventory_status (재고 현황) 📝 완전성: - 총 30+ 테이블, 50+ 인덱스, 6개 뷰, 10+ 함수 - 모든 backend/scripts SQL 파일 통합 완료 - 다른 환경 배포 시 한 번에 모든 테이블 생성 가능
This commit is contained in:
@@ -50,7 +50,18 @@ CREATE TABLE IF NOT EXISTS files (
|
||||
|
||||
-- 추가 필드 (19_add_user_tracking_fields.sql)
|
||||
updated_by VARCHAR(100),
|
||||
bom_name VARCHAR(200) -- BOM 이름 필드 추가
|
||||
bom_name VARCHAR(200), -- BOM 이름 필드 추가
|
||||
|
||||
-- 분류 관련 필드 (05_add_classification_columns.sql)
|
||||
classification_stats JSONB,
|
||||
classification_completed BOOLEAN DEFAULT FALSE,
|
||||
classification_timestamp TIMESTAMP,
|
||||
|
||||
-- Job 연결 필드 (02_modify_files_table.sql)
|
||||
job_no VARCHAR(50),
|
||||
|
||||
-- 파싱 통계 필드
|
||||
parsed_count INTEGER DEFAULT 0
|
||||
);
|
||||
|
||||
-- 개별 자재 상세 정보
|
||||
@@ -103,8 +114,14 @@ CREATE TABLE IF NOT EXISTS materials (
|
||||
classified_at TIMESTAMP,
|
||||
updated_by VARCHAR(100),
|
||||
|
||||
-- 해시 필드 (재료 추적용)
|
||||
-- 분류 상세 필드 (05_add_classification_columns.sql)
|
||||
subcategory VARCHAR(100),
|
||||
standard VARCHAR(200),
|
||||
grade VARCHAR(200),
|
||||
|
||||
-- 해시 필드 (10_add_material_comparison_system.sql)
|
||||
material_hash VARCHAR(64),
|
||||
normalized_description TEXT,
|
||||
|
||||
-- 기타
|
||||
drawing_reference VARCHAR(100),
|
||||
@@ -584,7 +601,362 @@ CREATE TABLE IF NOT EXISTS material_purchase_tracking (
|
||||
);
|
||||
|
||||
-- ================================
|
||||
-- 6. 사용자 활동 로그 테이블 (19_add_user_tracking_fields.sql)
|
||||
-- 6. Jobs 테이블 (01_create_jobs_table.sql)
|
||||
-- ================================
|
||||
|
||||
CREATE TABLE IF NOT EXISTS jobs (
|
||||
-- 기본 정보
|
||||
job_no VARCHAR(50) PRIMARY KEY,
|
||||
job_name VARCHAR(200) NOT NULL,
|
||||
|
||||
-- 계약 관계 (핵심)
|
||||
client_name VARCHAR(100) NOT NULL,
|
||||
|
||||
-- 프로젝트 정보
|
||||
end_user VARCHAR(100),
|
||||
epc_company VARCHAR(100),
|
||||
project_site VARCHAR(200),
|
||||
|
||||
-- 상업 정보
|
||||
contract_date DATE,
|
||||
delivery_date DATE,
|
||||
delivery_terms VARCHAR(100),
|
||||
|
||||
-- 상태 관리 (핵심)
|
||||
status VARCHAR(20) DEFAULT '진행중',
|
||||
delivery_completed_date DATE,
|
||||
project_closed_date DATE,
|
||||
|
||||
-- 관리 정보
|
||||
description TEXT,
|
||||
created_by VARCHAR(50),
|
||||
created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
|
||||
updated_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
|
||||
is_active BOOLEAN DEFAULT true,
|
||||
|
||||
-- 사용자 추적 필드 (19_add_user_tracking_fields.sql)
|
||||
updated_by VARCHAR(100),
|
||||
assigned_to VARCHAR(100),
|
||||
|
||||
-- 프로젝트 타입 필드 (17_add_project_type_column.sql)
|
||||
project_type VARCHAR(50) DEFAULT '냉동기' NOT NULL
|
||||
);
|
||||
|
||||
-- ================================
|
||||
-- 7. 자재 규격/재질 기준표 테이블들 (05_create_material_standards_tables.sql)
|
||||
-- ================================
|
||||
|
||||
-- 자재 규격 표준 테이블
|
||||
CREATE TABLE IF NOT EXISTS material_standards (
|
||||
id SERIAL PRIMARY KEY,
|
||||
standard_code VARCHAR(20) UNIQUE NOT NULL,
|
||||
standard_name VARCHAR(100) NOT NULL,
|
||||
description TEXT,
|
||||
country VARCHAR(50),
|
||||
is_active BOOLEAN DEFAULT TRUE,
|
||||
created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
|
||||
updated_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP
|
||||
);
|
||||
|
||||
-- 제조방식별 카테고리 테이블
|
||||
CREATE TABLE IF NOT EXISTS material_categories (
|
||||
id SERIAL PRIMARY KEY,
|
||||
standard_id INTEGER REFERENCES material_standards(id),
|
||||
category_code VARCHAR(50) NOT NULL,
|
||||
category_name VARCHAR(100) NOT NULL,
|
||||
description TEXT,
|
||||
is_active BOOLEAN DEFAULT TRUE,
|
||||
created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
|
||||
updated_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP
|
||||
);
|
||||
|
||||
-- 구체적인 규격 테이블
|
||||
CREATE TABLE IF NOT EXISTS material_specifications (
|
||||
id SERIAL PRIMARY KEY,
|
||||
category_id INTEGER REFERENCES material_categories(id),
|
||||
spec_code VARCHAR(20) NOT NULL,
|
||||
spec_name VARCHAR(100) NOT NULL,
|
||||
description TEXT,
|
||||
material_type VARCHAR(50),
|
||||
manufacturing VARCHAR(50),
|
||||
pressure_rating VARCHAR(100),
|
||||
is_active BOOLEAN DEFAULT TRUE,
|
||||
created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
|
||||
updated_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP
|
||||
);
|
||||
|
||||
-- 등급별 상세 정보 테이블
|
||||
CREATE TABLE IF NOT EXISTS material_grades (
|
||||
id SERIAL PRIMARY KEY,
|
||||
specification_id INTEGER REFERENCES material_specifications(id),
|
||||
grade_code VARCHAR(20) NOT NULL,
|
||||
grade_name VARCHAR(100),
|
||||
composition VARCHAR(200),
|
||||
applications VARCHAR(200),
|
||||
temp_max VARCHAR(50),
|
||||
temp_range VARCHAR(100),
|
||||
yield_strength VARCHAR(50),
|
||||
tensile_strength VARCHAR(50),
|
||||
corrosion_resistance VARCHAR(50),
|
||||
stabilizer VARCHAR(50),
|
||||
base_grade VARCHAR(20),
|
||||
is_active BOOLEAN DEFAULT TRUE,
|
||||
created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
|
||||
updated_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP
|
||||
);
|
||||
|
||||
-- 정규식 패턴 테이블
|
||||
CREATE TABLE IF NOT EXISTS material_patterns (
|
||||
id SERIAL PRIMARY KEY,
|
||||
specification_id INTEGER REFERENCES material_specifications(id),
|
||||
pattern TEXT NOT NULL,
|
||||
description VARCHAR(200),
|
||||
priority INTEGER DEFAULT 1,
|
||||
is_active BOOLEAN DEFAULT TRUE,
|
||||
created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
|
||||
updated_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP
|
||||
);
|
||||
|
||||
-- 특수 재질 테이블
|
||||
CREATE TABLE IF NOT EXISTS special_materials (
|
||||
id SERIAL PRIMARY KEY,
|
||||
material_type VARCHAR(50) NOT NULL,
|
||||
material_name VARCHAR(100) NOT NULL,
|
||||
description TEXT,
|
||||
composition VARCHAR(200),
|
||||
applications TEXT,
|
||||
temp_max VARCHAR(50),
|
||||
manufacturing VARCHAR(50),
|
||||
is_active BOOLEAN DEFAULT TRUE,
|
||||
created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
|
||||
updated_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP
|
||||
);
|
||||
|
||||
-- 특수 재질 등급 테이블
|
||||
CREATE TABLE IF NOT EXISTS special_material_grades (
|
||||
id SERIAL PRIMARY KEY,
|
||||
material_id INTEGER REFERENCES special_materials(id),
|
||||
grade_code VARCHAR(20) NOT NULL,
|
||||
composition VARCHAR(200),
|
||||
applications VARCHAR(200),
|
||||
temp_max VARCHAR(50),
|
||||
strength VARCHAR(50),
|
||||
purity VARCHAR(100),
|
||||
corrosion VARCHAR(50),
|
||||
is_active BOOLEAN DEFAULT TRUE,
|
||||
created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
|
||||
updated_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP
|
||||
);
|
||||
|
||||
-- 특수 재질 정규식 패턴 테이블
|
||||
CREATE TABLE IF NOT EXISTS special_material_patterns (
|
||||
id SERIAL PRIMARY KEY,
|
||||
material_id INTEGER REFERENCES special_materials(id),
|
||||
pattern TEXT NOT NULL,
|
||||
description VARCHAR(200),
|
||||
priority INTEGER DEFAULT 1,
|
||||
is_active BOOLEAN DEFAULT TRUE,
|
||||
created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
|
||||
updated_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP
|
||||
);
|
||||
|
||||
-- ================================
|
||||
-- 8. 자재 비교 및 발주 추적 시스템 (10_add_material_comparison_system.sql)
|
||||
-- ================================
|
||||
|
||||
-- 자재 비교 결과 저장 테이블
|
||||
CREATE TABLE IF NOT EXISTS material_revisions_comparison (
|
||||
id SERIAL PRIMARY KEY,
|
||||
|
||||
-- 비교 기본 정보
|
||||
job_no VARCHAR(50) NOT NULL,
|
||||
current_revision VARCHAR(20) NOT NULL,
|
||||
previous_revision VARCHAR(20) NOT NULL,
|
||||
current_file_id INTEGER NOT NULL,
|
||||
previous_file_id INTEGER NOT NULL,
|
||||
|
||||
-- 비교 결과 요약
|
||||
total_current_items INTEGER DEFAULT 0,
|
||||
total_previous_items INTEGER DEFAULT 0,
|
||||
new_items_count INTEGER DEFAULT 0,
|
||||
modified_items_count INTEGER DEFAULT 0,
|
||||
removed_items_count INTEGER DEFAULT 0,
|
||||
unchanged_items_count INTEGER DEFAULT 0,
|
||||
|
||||
-- 상세 결과 (JSON)
|
||||
comparison_details JSONB,
|
||||
|
||||
-- 관리 정보
|
||||
created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
|
||||
created_by VARCHAR(100),
|
||||
|
||||
-- 외래키
|
||||
FOREIGN KEY (current_file_id) REFERENCES files(id),
|
||||
FOREIGN KEY (previous_file_id) REFERENCES files(id),
|
||||
|
||||
-- 유니크 제약 (같은 비교는 한 번만)
|
||||
UNIQUE(job_no, current_revision, previous_revision)
|
||||
);
|
||||
|
||||
-- 개별 자재 비교 상세 테이블
|
||||
CREATE TABLE IF NOT EXISTS material_comparison_details (
|
||||
id SERIAL PRIMARY KEY,
|
||||
|
||||
comparison_id INTEGER NOT NULL,
|
||||
material_hash VARCHAR(32) NOT NULL,
|
||||
|
||||
-- 비교 타입
|
||||
change_type VARCHAR(20) NOT NULL, -- 'NEW', 'MODIFIED', 'REMOVED', 'UNCHANGED'
|
||||
|
||||
-- 자재 정보
|
||||
description TEXT NOT NULL,
|
||||
size_spec VARCHAR(100),
|
||||
material_grade VARCHAR(100),
|
||||
|
||||
-- 수량 비교
|
||||
previous_quantity DECIMAL(10,3) DEFAULT 0,
|
||||
current_quantity DECIMAL(10,3) DEFAULT 0,
|
||||
quantity_diff DECIMAL(10,3) DEFAULT 0,
|
||||
|
||||
-- 추가 구매 필요량 (핵심!)
|
||||
additional_purchase_needed DECIMAL(10,3) DEFAULT 0,
|
||||
|
||||
-- 분류 정보
|
||||
classified_category VARCHAR(50),
|
||||
classification_confidence DECIMAL(3,2),
|
||||
|
||||
-- 관리 정보
|
||||
created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
|
||||
|
||||
-- 외래키
|
||||
FOREIGN KEY (comparison_id) REFERENCES material_revisions_comparison(id) ON DELETE CASCADE
|
||||
);
|
||||
|
||||
-- ================================
|
||||
-- 9. Tubing 시스템 테이블들 (15_create_tubing_system.sql)
|
||||
-- ================================
|
||||
|
||||
-- Tubing 카테고리 테이블
|
||||
CREATE TABLE IF NOT EXISTS tubing_categories (
|
||||
id SERIAL PRIMARY KEY,
|
||||
category_code VARCHAR(20) UNIQUE NOT NULL,
|
||||
category_name VARCHAR(100) NOT NULL,
|
||||
description TEXT,
|
||||
is_active BOOLEAN DEFAULT TRUE,
|
||||
created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
|
||||
updated_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP
|
||||
);
|
||||
|
||||
-- Tubing 규격 마스터 테이블
|
||||
CREATE TABLE IF NOT EXISTS tubing_specifications (
|
||||
id SERIAL PRIMARY KEY,
|
||||
category_id INTEGER REFERENCES tubing_categories(id),
|
||||
spec_code VARCHAR(50) UNIQUE NOT NULL,
|
||||
spec_name VARCHAR(200) NOT NULL,
|
||||
|
||||
-- 물리적 규격
|
||||
outer_diameter_mm DECIMAL(8,3), -- 외경 (mm)
|
||||
wall_thickness_mm DECIMAL(6,3), -- 두께 (mm)
|
||||
inner_diameter_mm DECIMAL(8,3), -- 내경 (mm, 계산 또는 실측)
|
||||
|
||||
-- 재질 정보
|
||||
material_grade VARCHAR(100), -- SS316, SS316L, Inconel625 등
|
||||
material_standard VARCHAR(100), -- ASTM A269, JIS G3463 등
|
||||
|
||||
-- 압력/온도 등급
|
||||
max_pressure_bar DECIMAL(8,2), -- 최대 압력 (bar)
|
||||
max_temperature_c DECIMAL(6,2), -- 최대 온도 (°C)
|
||||
min_temperature_c DECIMAL(6,2), -- 최소 온도 (°C)
|
||||
|
||||
-- 표준 규격
|
||||
standard_length_m DECIMAL(8,3), -- 표준 길이 (m)
|
||||
bend_radius_min_mm DECIMAL(8,2), -- 최소 벤딩 반경 (mm)
|
||||
|
||||
-- 기타 정보
|
||||
surface_finish VARCHAR(100), -- 표면 마감 (BA, #4, 2B 등)
|
||||
hardness VARCHAR(50), -- 경도
|
||||
notes TEXT,
|
||||
|
||||
is_active BOOLEAN DEFAULT TRUE,
|
||||
created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
|
||||
updated_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP
|
||||
);
|
||||
|
||||
-- 제조사 정보 테이블
|
||||
CREATE TABLE IF NOT EXISTS tubing_manufacturers (
|
||||
id SERIAL PRIMARY KEY,
|
||||
manufacturer_code VARCHAR(20) UNIQUE NOT NULL,
|
||||
manufacturer_name VARCHAR(200) NOT NULL,
|
||||
country VARCHAR(100),
|
||||
website VARCHAR(500),
|
||||
contact_info JSONB, -- 연락처 정보 (JSON)
|
||||
quality_certs JSONB, -- 품질 인증서 정보 (ISO, API 등)
|
||||
is_active BOOLEAN DEFAULT TRUE,
|
||||
created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
|
||||
updated_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP
|
||||
);
|
||||
|
||||
-- 제조사별 제품 테이블
|
||||
CREATE TABLE IF NOT EXISTS tubing_products (
|
||||
id SERIAL PRIMARY KEY,
|
||||
specification_id INTEGER REFERENCES tubing_specifications(id),
|
||||
manufacturer_id INTEGER REFERENCES tubing_manufacturers(id),
|
||||
|
||||
-- 제조사 품목번호 정보
|
||||
manufacturer_part_number VARCHAR(200) NOT NULL, -- 제조사 품목번호
|
||||
manufacturer_product_name VARCHAR(300), -- 제조사 제품명
|
||||
|
||||
-- 가격/공급 정보
|
||||
list_price DECIMAL(12,2), -- 정가
|
||||
currency VARCHAR(10) DEFAULT 'KRW', -- 통화
|
||||
lead_time_days INTEGER, -- 리드타임 (일)
|
||||
minimum_order_qty DECIMAL(10,3), -- 최소 주문 수량
|
||||
standard_packaging_qty DECIMAL(10,3), -- 표준 포장 수량
|
||||
|
||||
-- 가용성 정보
|
||||
availability_status VARCHAR(50), -- 재고 상태
|
||||
last_price_update DATE, -- 마지막 가격 업데이트
|
||||
|
||||
-- 추가 정보
|
||||
datasheet_url VARCHAR(500), -- 데이터시트 URL
|
||||
catalog_page VARCHAR(100), -- 카탈로그 페이지
|
||||
notes TEXT,
|
||||
|
||||
is_active BOOLEAN DEFAULT TRUE,
|
||||
created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
|
||||
updated_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
|
||||
|
||||
-- 유니크 제약 (같은 규격의 같은 제조사 제품은 하나만)
|
||||
UNIQUE(specification_id, manufacturer_id, manufacturer_part_number)
|
||||
);
|
||||
|
||||
-- BOM에서 사용되는 Tubing 매핑 테이블
|
||||
CREATE TABLE IF NOT EXISTS material_tubing_mapping (
|
||||
id SERIAL PRIMARY KEY,
|
||||
material_id INTEGER REFERENCES materials(id) ON DELETE CASCADE,
|
||||
tubing_product_id INTEGER REFERENCES tubing_products(id),
|
||||
|
||||
-- 매핑 정보
|
||||
confidence_score DECIMAL(3,2), -- 매핑 신뢰도 (0.00-1.00)
|
||||
mapping_method VARCHAR(50), -- 매핑 방법 (auto/manual)
|
||||
mapped_by VARCHAR(100), -- 매핑한 사용자
|
||||
mapped_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
|
||||
|
||||
-- 수량 정보
|
||||
required_length_m DECIMAL(10,3), -- 필요 길이 (m)
|
||||
calculated_quantity DECIMAL(10,3), -- 계산된 주문 수량
|
||||
|
||||
-- 검증 정보
|
||||
is_verified BOOLEAN DEFAULT FALSE,
|
||||
verified_by VARCHAR(100),
|
||||
verified_at TIMESTAMP,
|
||||
|
||||
notes TEXT,
|
||||
created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP
|
||||
);
|
||||
|
||||
-- ================================
|
||||
-- 10. 사용자 활동 로그 테이블 (19_add_user_tracking_fields.sql)
|
||||
-- ================================
|
||||
|
||||
CREATE TABLE IF NOT EXISTS user_activity_logs (
|
||||
@@ -693,12 +1065,87 @@ CREATE INDEX IF NOT EXISTS idx_material_purchase_mapping_purchase ON material_pu
|
||||
CREATE INDEX IF NOT EXISTS idx_material_purchase_tracking_hash ON material_purchase_tracking(material_hash);
|
||||
CREATE INDEX IF NOT EXISTS idx_material_purchase_tracking_job_revision ON material_purchase_tracking(job_no, revision);
|
||||
|
||||
-- Jobs 테이블 인덱스
|
||||
CREATE INDEX IF NOT EXISTS idx_jobs_status ON jobs(status);
|
||||
CREATE INDEX IF NOT EXISTS idx_jobs_client ON jobs(client_name);
|
||||
CREATE INDEX IF NOT EXISTS idx_jobs_created_at ON jobs(created_at);
|
||||
CREATE INDEX IF NOT EXISTS idx_jobs_created_by ON jobs(created_by);
|
||||
CREATE INDEX IF NOT EXISTS idx_jobs_assigned_to ON jobs(assigned_to);
|
||||
|
||||
-- 자재 규격/재질 기준표 인덱스
|
||||
CREATE INDEX IF NOT EXISTS idx_material_standards_code ON material_standards(standard_code);
|
||||
CREATE INDEX IF NOT EXISTS idx_material_categories_standard ON material_categories(standard_id);
|
||||
CREATE INDEX IF NOT EXISTS idx_material_specifications_category ON material_specifications(category_id);
|
||||
CREATE INDEX IF NOT EXISTS idx_material_grades_specification ON material_grades(specification_id);
|
||||
CREATE INDEX IF NOT EXISTS idx_material_patterns_specification ON material_patterns(specification_id);
|
||||
CREATE INDEX IF NOT EXISTS idx_special_materials_type ON special_materials(material_type);
|
||||
CREATE INDEX IF NOT EXISTS idx_special_material_grades_material ON special_material_grades(material_id);
|
||||
CREATE INDEX IF NOT EXISTS idx_special_material_patterns_material ON special_material_patterns(material_id);
|
||||
|
||||
-- 활성 상태 인덱스
|
||||
CREATE INDEX IF NOT EXISTS idx_material_standards_active ON material_standards(is_active);
|
||||
CREATE INDEX IF NOT EXISTS idx_material_categories_active ON material_categories(is_active);
|
||||
CREATE INDEX IF NOT EXISTS idx_material_specifications_active ON material_specifications(is_active);
|
||||
CREATE INDEX IF NOT EXISTS idx_material_grades_active ON material_grades(is_active);
|
||||
CREATE INDEX IF NOT EXISTS idx_material_patterns_active ON material_patterns(is_active);
|
||||
CREATE INDEX IF NOT EXISTS idx_special_materials_active ON special_materials(is_active);
|
||||
CREATE INDEX IF NOT EXISTS idx_special_material_grades_active ON special_material_grades(is_active);
|
||||
CREATE INDEX IF NOT EXISTS idx_special_material_patterns_active ON special_material_patterns(is_active);
|
||||
|
||||
-- 자재 비교 시스템 인덱스
|
||||
CREATE INDEX IF NOT EXISTS idx_material_revisions_job ON material_revisions_comparison(job_no);
|
||||
CREATE INDEX IF NOT EXISTS idx_material_revisions_current ON material_revisions_comparison(current_revision);
|
||||
CREATE INDEX IF NOT EXISTS idx_material_comparison_hash ON material_comparison_details(material_hash);
|
||||
CREATE INDEX IF NOT EXISTS idx_material_comparison_type ON material_comparison_details(change_type);
|
||||
|
||||
-- Tubing 시스템 인덱스
|
||||
CREATE INDEX IF NOT EXISTS idx_tubing_specs_category ON tubing_specifications(category_id);
|
||||
CREATE INDEX IF NOT EXISTS idx_tubing_specs_material ON tubing_specifications(material_grade);
|
||||
CREATE INDEX IF NOT EXISTS idx_tubing_specs_diameter ON tubing_specifications(outer_diameter_mm, wall_thickness_mm);
|
||||
CREATE INDEX IF NOT EXISTS idx_tubing_products_spec ON tubing_products(specification_id);
|
||||
CREATE INDEX IF NOT EXISTS idx_tubing_products_manufacturer ON tubing_products(manufacturer_id);
|
||||
CREATE INDEX IF NOT EXISTS idx_tubing_products_part_number ON tubing_products(manufacturer_part_number);
|
||||
CREATE INDEX IF NOT EXISTS idx_material_tubing_mapping_material ON material_tubing_mapping(material_id);
|
||||
CREATE INDEX IF NOT EXISTS idx_material_tubing_mapping_product ON material_tubing_mapping(tubing_product_id);
|
||||
|
||||
-- 사용자 활동 로그 인덱스
|
||||
CREATE INDEX IF NOT EXISTS idx_user_activity_logs_username ON user_activity_logs(username);
|
||||
CREATE INDEX IF NOT EXISTS idx_user_activity_logs_activity_type ON user_activity_logs(activity_type);
|
||||
CREATE INDEX IF NOT EXISTS idx_user_activity_logs_created_at ON user_activity_logs(created_at);
|
||||
CREATE INDEX IF NOT EXISTS idx_user_activity_logs_target ON user_activity_logs(target_type, target_id);
|
||||
|
||||
-- ================================
|
||||
-- 추가 성능 최적화 인덱스 (16_performance_indexes.sql)
|
||||
-- ================================
|
||||
|
||||
-- 복합 인덱스 (자주 함께 사용되는 컬럼들)
|
||||
CREATE INDEX IF NOT EXISTS idx_files_job_revision ON files(job_no, revision) WHERE is_active = true;
|
||||
CREATE INDEX IF NOT EXISTS idx_files_job_date ON files(job_no, upload_date DESC) WHERE is_active = true;
|
||||
CREATE INDEX IF NOT EXISTS idx_materials_file_category ON materials(file_id, classified_category);
|
||||
CREATE INDEX IF NOT EXISTS idx_materials_category_grade ON materials(classified_category, material_grade);
|
||||
|
||||
-- 검색 성능 향상 인덱스
|
||||
CREATE INDEX IF NOT EXISTS idx_materials_description_gin ON materials USING gin(to_tsvector('english', original_description));
|
||||
|
||||
-- 정렬 성능 향상 인덱스
|
||||
CREATE INDEX IF NOT EXISTS idx_jobs_status_created ON jobs(status, created_at DESC) WHERE is_active = true;
|
||||
CREATE INDEX IF NOT EXISTS idx_materials_quantity_desc ON materials(quantity DESC);
|
||||
|
||||
-- 조건부 인덱스 (특정 조건에서만 사용)
|
||||
CREATE INDEX IF NOT EXISTS idx_materials_unverified ON materials(classified_category, classification_confidence) WHERE is_verified = false;
|
||||
CREATE INDEX IF NOT EXISTS idx_materials_low_confidence ON materials(file_id, classified_category) WHERE classification_confidence < 0.8;
|
||||
|
||||
-- 분류 관련 인덱스 (05_add_classification_columns.sql)
|
||||
CREATE INDEX IF NOT EXISTS idx_materials_subcategory ON materials(subcategory);
|
||||
CREATE INDEX IF NOT EXISTS idx_materials_standard ON materials(standard);
|
||||
CREATE INDEX IF NOT EXISTS idx_materials_grade ON materials(grade);
|
||||
|
||||
-- Job 연결 인덱스 (02_modify_files_table.sql)
|
||||
CREATE INDEX IF NOT EXISTS idx_files_job_no ON files(job_no);
|
||||
|
||||
-- 프로젝트 타입 인덱스 (17_add_project_type_column.sql)
|
||||
CREATE INDEX IF NOT EXISTS idx_jobs_project_type ON jobs(project_type);
|
||||
|
||||
-- ================================
|
||||
-- 8. 트리거 함수 및 트리거 생성
|
||||
-- ================================
|
||||
@@ -754,6 +1201,49 @@ CREATE TRIGGER IF NOT EXISTS trigger_update_purchase_items_timestamp BEFORE UPDA
|
||||
CREATE TRIGGER IF NOT EXISTS trigger_files_updated_at BEFORE UPDATE ON files
|
||||
FOR EACH ROW EXECUTE FUNCTION update_files_updated_at();
|
||||
|
||||
-- ================================
|
||||
-- 해시 생성 함수 및 트리거 (10_add_material_comparison_system.sql)
|
||||
-- ================================
|
||||
|
||||
-- 해시 생성 함수
|
||||
CREATE OR REPLACE FUNCTION generate_material_hash(
|
||||
description TEXT,
|
||||
size_spec TEXT DEFAULT '',
|
||||
material_grade TEXT DEFAULT ''
|
||||
) RETURNS VARCHAR(32) AS $$
|
||||
BEGIN
|
||||
-- 정규화: 대소문자 통일, 공백 정리
|
||||
description := UPPER(TRIM(REGEXP_REPLACE(description, '\s+', ' ', 'g')));
|
||||
size_spec := UPPER(TRIM(COALESCE(size_spec, '')));
|
||||
material_grade := UPPER(TRIM(COALESCE(material_grade, '')));
|
||||
|
||||
-- MD5 해시 생성 (32자리)
|
||||
RETURN MD5(description || '|' || size_spec || '|' || material_grade);
|
||||
END;
|
||||
$$ LANGUAGE plpgsql;
|
||||
|
||||
-- 자동 해시 생성 트리거 함수
|
||||
CREATE OR REPLACE FUNCTION auto_generate_material_hash()
|
||||
RETURNS TRIGGER AS $$
|
||||
BEGIN
|
||||
-- 새로 삽입되거나 업데이트될 때 자동으로 해시 생성
|
||||
NEW.material_hash := generate_material_hash(
|
||||
NEW.original_description,
|
||||
NEW.size_spec,
|
||||
NEW.material_grade
|
||||
);
|
||||
NEW.normalized_description := UPPER(TRIM(REGEXP_REPLACE(NEW.original_description, '\s+', ' ', 'g')));
|
||||
|
||||
RETURN NEW;
|
||||
END;
|
||||
$$ LANGUAGE plpgsql;
|
||||
|
||||
-- 자동 해시 생성 트리거 적용
|
||||
CREATE TRIGGER IF NOT EXISTS trigger_auto_material_hash
|
||||
BEFORE INSERT OR UPDATE ON materials
|
||||
FOR EACH ROW
|
||||
EXECUTE FUNCTION auto_generate_material_hash();
|
||||
|
||||
-- ================================
|
||||
-- 9. 기본 데이터 삽입
|
||||
-- ================================
|
||||
@@ -843,6 +1333,30 @@ INSERT INTO projects (official_project_code, project_name, client_name, status,
|
||||
('TK-MP-TEST-001', 'TK-MP 테스트 프로젝트', 'Test Client', 'active', '기능 테스트용 프로젝트')
|
||||
ON CONFLICT (official_project_code) DO NOTHING;
|
||||
|
||||
-- Tubing 카테고리 기초 데이터
|
||||
INSERT INTO tubing_categories (category_code, category_name, description) VALUES
|
||||
('GENERAL', '일반 Tubing', '일반적인 스테인리스 스틸 튜빙'),
|
||||
('VCR', 'VCR Tubing', 'VCR (Vacuum Coupling Radiation) 연결용 튜빙'),
|
||||
('SANITARY', 'Sanitary Tubing', '위생용 튜빙 (식품, 제약 등)'),
|
||||
('HVAC', 'HVAC Tubing', '공조용 튜빙'),
|
||||
('HYDRAULIC', 'Hydraulic Tubing', '유압용 튜빙'),
|
||||
('PNEUMATIC', 'Pneumatic Tubing', '공압용 튜빙'),
|
||||
('PROCESS', 'Process Tubing', '공정용 특수 튜빙'),
|
||||
('EXOTIC', 'Exotic Material', '특수 재질 튜빙 (Hastelloy, Inconel 등)')
|
||||
ON CONFLICT (category_code) DO NOTHING;
|
||||
|
||||
-- 주요 제조사 기초 데이터
|
||||
INSERT INTO tubing_manufacturers (manufacturer_code, manufacturer_name, country) VALUES
|
||||
('SWAGELOK', 'Swagelok Company', 'USA'),
|
||||
('PARKER', 'Parker Hannifin', 'USA'),
|
||||
('HAM_LET', 'Ham-Let Group', 'Israel'),
|
||||
('SUPERLOK', 'Superlok USA', 'USA'),
|
||||
('FITOK', 'Fitok Group', 'China'),
|
||||
('DK_LOK', 'DK-Lok Corporation', 'South Korea'),
|
||||
('GYROLOK', 'Gyrolok (Oliver Valves)', 'UK'),
|
||||
('AS_ONE', 'AS ONE Corporation', 'Japan')
|
||||
ON CONFLICT (manufacturer_code) DO NOTHING;
|
||||
|
||||
-- ================================
|
||||
-- 10. 뷰 생성
|
||||
-- ================================
|
||||
@@ -885,23 +1399,103 @@ LEFT JOIN login_logs ll ON u.user_id = ll.user_id AND ll.login_status = 'success
|
||||
GROUP BY u.user_id, u.username, u.name, u.email, u.role, u.access_level,
|
||||
u.department, u.position, u.is_active, u.created_at, u.last_login_at;
|
||||
|
||||
-- ================================
|
||||
-- 추가 뷰들 (05_add_classification_columns.sql, 10_add_material_comparison_system.sql)
|
||||
-- ================================
|
||||
|
||||
-- 분류 결과 통계 조회용 뷰
|
||||
CREATE OR REPLACE VIEW classification_summary AS
|
||||
SELECT
|
||||
f.job_no,
|
||||
f.original_filename,
|
||||
f.parsed_count,
|
||||
f.classification_completed,
|
||||
f.classification_timestamp,
|
||||
COUNT(*) as total_materials,
|
||||
COUNT(CASE WHEN m.classified_category = 'BOLT' THEN 1 END) as bolt_count,
|
||||
COUNT(CASE WHEN m.classified_category = 'FLANGE' THEN 1 END) as flange_count,
|
||||
COUNT(CASE WHEN m.classified_category = 'FITTING' THEN 1 END) as fitting_count,
|
||||
COUNT(CASE WHEN m.classified_category = 'GASKET' THEN 1 END) as gasket_count,
|
||||
COUNT(CASE WHEN m.classified_category = 'INSTRUMENT' THEN 1 END) as instrument_count,
|
||||
COUNT(CASE WHEN m.classified_category = 'PIPE' THEN 1 END) as pipe_count,
|
||||
COUNT(CASE WHEN m.classified_category = 'VALVE' THEN 1 END) as valve_count,
|
||||
COUNT(CASE WHEN m.classified_category = 'MATERIAL' THEN 1 END) as material_count,
|
||||
COUNT(CASE WHEN m.classified_category = 'OTHER' THEN 1 END) as other_count,
|
||||
AVG(m.classification_confidence) as avg_confidence,
|
||||
COUNT(CASE WHEN m.is_verified = TRUE THEN 1 END) as verified_count
|
||||
FROM files f
|
||||
LEFT JOIN materials m ON f.id = m.file_id
|
||||
WHERE f.is_active = TRUE
|
||||
GROUP BY f.id, f.job_no, f.original_filename, f.parsed_count, f.classification_completed, f.classification_timestamp;
|
||||
|
||||
-- 분류 성능 통계 뷰
|
||||
CREATE OR REPLACE VIEW classification_performance AS
|
||||
SELECT
|
||||
classified_category,
|
||||
subcategory,
|
||||
standard,
|
||||
COUNT(*) as total_count,
|
||||
AVG(classification_confidence) as avg_confidence,
|
||||
COUNT(CASE WHEN is_verified = TRUE THEN 1 END) as verified_count,
|
||||
COUNT(CASE WHEN is_verified = FALSE THEN 1 END) as unverified_count,
|
||||
ROUND(
|
||||
(COUNT(CASE WHEN is_verified = TRUE THEN 1 END)::DECIMAL / COUNT(*) * 100), 2
|
||||
) as verification_rate
|
||||
FROM materials
|
||||
WHERE classified_category IS NOT NULL
|
||||
GROUP BY classified_category, subcategory, standard
|
||||
ORDER BY total_count DESC;
|
||||
|
||||
-- 누적 재고 현황 뷰 (10_add_material_comparison_system.sql)
|
||||
CREATE OR REPLACE VIEW material_inventory_status AS
|
||||
SELECT
|
||||
mpt.job_no,
|
||||
mpt.material_hash,
|
||||
mpt.description,
|
||||
mpt.size_spec,
|
||||
mpt.unit,
|
||||
|
||||
-- 누적 수량
|
||||
SUM(mpt.confirmed_quantity) as total_confirmed,
|
||||
SUM(mpt.ordered_quantity) as total_ordered,
|
||||
SUM(mpt.received_quantity) as total_received,
|
||||
|
||||
-- 현재 가용 재고
|
||||
SUM(mpt.received_quantity) as available_stock,
|
||||
|
||||
-- 최신 리비전 정보
|
||||
MAX(mpt.revision) as latest_revision,
|
||||
MAX(mpt.updated_at) as last_updated
|
||||
|
||||
FROM material_purchase_tracking mpt
|
||||
WHERE mpt.purchase_status != 'CANCELLED'
|
||||
GROUP BY mpt.job_no, mpt.material_hash, mpt.description, mpt.size_spec, mpt.unit;
|
||||
|
||||
-- ================================
|
||||
-- 완료 메시지
|
||||
-- ================================
|
||||
|
||||
DO $$
|
||||
BEGIN
|
||||
RAISE NOTICE '✅ TK-MP-Project 통합 데이터베이스 스키마가 성공적으로 생성되었습니다!';
|
||||
RAISE NOTICE '✅ TK-MP-Project 완전 통합 데이터베이스 스키마가 성공적으로 생성되었습니다!';
|
||||
RAISE NOTICE '📋 생성된 주요 테이블:';
|
||||
RAISE NOTICE ' - 기본: projects, files, materials';
|
||||
RAISE NOTICE ' - 기본: projects, files, materials, jobs';
|
||||
RAISE NOTICE ' - 자재상세: pipe_details, fitting_details, valve_details, flange_details, bolt_details, gasket_details, instrument_details';
|
||||
RAISE NOTICE ' - 파이프: pipe_end_preparations';
|
||||
RAISE NOTICE ' - 인증: users, login_logs, user_sessions, permissions, role_permissions';
|
||||
RAISE NOTICE ' - 구매: purchase_items, material_purchase_mapping, material_purchase_tracking';
|
||||
RAISE NOTICE ' - 자재규격: material_standards, material_categories, material_specifications, material_grades, material_patterns';
|
||||
RAISE NOTICE ' - 특수재질: special_materials, special_material_grades, special_material_patterns';
|
||||
RAISE NOTICE ' - 비교시스템: material_revisions_comparison, material_comparison_details';
|
||||
RAISE NOTICE ' - Tubing: tubing_categories, tubing_specifications, tubing_manufacturers, tubing_products, material_tubing_mapping';
|
||||
RAISE NOTICE ' - 로그: user_activity_logs';
|
||||
RAISE NOTICE '👤 기본 계정: admin/admin123, system/admin123';
|
||||
RAISE NOTICE '🏗️ 기본 프로젝트: TK-MP-DEV-001, TK-MP-DEMO-001, TK-MP-TEST-001';
|
||||
RAISE NOTICE '🏭 기본 Tubing 제조사: SWAGELOK, PARKER, HAM_LET, SUPERLOK, FITOK, DK_LOK, GYROLOK, AS_ONE';
|
||||
RAISE NOTICE '🔐 권한 시스템: 5단계 역할 + 모듈별 세분화된 권한';
|
||||
RAISE NOTICE '📊 성능 최적화: 모든 주요 컬럼에 인덱스 적용';
|
||||
RAISE NOTICE '🔄 자동화: updated_at 트리거 및 기본 데이터 자동 생성';
|
||||
RAISE NOTICE '📊 성능 최적화: 복합인덱스, GIN인덱스, 조건부인덱스 포함 50+ 인덱스 적용';
|
||||
RAISE NOTICE '🔄 자동화: updated_at 트리거, 해시 자동생성, 기본 데이터 자동 생성';
|
||||
RAISE NOTICE '📈 통계뷰: classification_summary, classification_performance, material_inventory_status';
|
||||
RAISE NOTICE '🔧 함수: generate_material_hash, auto_generate_material_hash';
|
||||
RAISE NOTICE '📝 총 테이블 수: 30+개, 인덱스: 50+개, 뷰: 6개, 함수: 10+개';
|
||||
END $$;
|
||||
|
||||
Reference in New Issue
Block a user