refs #730: map carrier access groups to RDS performance
This commit is contained in:
@@ -95,6 +95,36 @@ View comment에 기록한다.
|
||||
각 View는 원격 소문자 컬럼을 Oracle의 일반 대문자 식별자로 명시적으로 alias한다. 따라서
|
||||
후속 SQL과 Select AI metadata에서는 큰따옴표 없이 안정적으로 사용할 수 있다.
|
||||
|
||||
### 5.4 기존 접근 그룹을 이용한 직원별 선사 배정
|
||||
|
||||
직원별 담당 선사는 신규 업무 테이블을 만들지 않고 기존 백오피스 접근 그룹 모델을
|
||||
재사용한다.
|
||||
|
||||
| 기존 객체 | 선사 배정에서의 역할 |
|
||||
|---|---|
|
||||
| `HMM_HR_EMPLOYEES` | 직원, 팀장, 팀 관계 |
|
||||
| `HMM_ACCESS_GROUPS` | `CARRIER_C001`부터 `CARRIER_C008`까지 선사 접근 그룹 |
|
||||
| `HMM_ACCESS_GROUP_MEMBERS` | 직원과 담당 선사의 연결 |
|
||||
| `HMM_CARRIER_ASSIGNMENTS_V` | 기존 세 테이블을 Select AI가 사용하기 쉬운 형태로 정규화 |
|
||||
|
||||
`HMM_CARRIER_ASSIGNMENTS_V.CARRIER_CODE`는 그룹 코드에서 `CARRIER_` 접두어를 제거해
|
||||
만들며, PostgreSQL 기반 `HMM_RDS_*_V.CARRIER_CODE`와 조인한다. 이 구조를 사용하면 기존
|
||||
백오피스의 접근 그룹 화면에서 담당자 변경이 가능하고 별도 관리 화면이나 중복 테이블이
|
||||
필요하지 않다.
|
||||
|
||||
`HMM_ACCESS_PERMISSION_RULES`는 행 접근 정책을 정의하는 보안 메타데이터이므로 담당 선사
|
||||
원장으로 사용하지 않는다.
|
||||
|
||||
Select AI가 이 관계를 추론에만 의존하지 않도록 네 View의 table comment와
|
||||
`CARRIER_CODE` column comment 양쪽에 상대 객체명과 조인 키를 기록한다.
|
||||
|
||||
- `HMM_CARRIER_ASSIGNMENTS_V.CARRIER_CODE`
|
||||
↔ `HMM_RDS_CARRIERS_V.CARRIER_CODE`
|
||||
- `HMM_CARRIER_ASSIGNMENTS_V.CARRIER_CODE`
|
||||
↔ `HMM_RDS_CARRIER_PERF_V.CARRIER_CODE`
|
||||
- `HMM_CARRIER_ASSIGNMENTS_V.CARRIER_CODE`
|
||||
↔ `HMM_RDS_CARRIER_LATEST_V.CARRIER_CODE`
|
||||
|
||||
## 6. 녹화용 실행 파일
|
||||
|
||||
| 순서 | 파일 | 화면에서 확인할 결과 |
|
||||
@@ -107,6 +137,8 @@ View comment에 기록한다.
|
||||
| 5 | `78_hmm_rds_pg_05_views.sql` | Oracle 로컬 View 3개 |
|
||||
| 6 | `79_hmm_rds_pg_06_verify.sql` | `8 / 144 / 8`, 위험도 3종 |
|
||||
| 재촬영 전 | `80_hmm_rds_pg_99_cleanup.sql` | View, DB Link, Credential만 제거 |
|
||||
| 7 | `81_hmm_carrier_access_groups.sql` | 선사 그룹 8건, 구성원 8건, federation 조인 8건 |
|
||||
| 8 | `82_hmm_federation_relationship_comments.sql` | 양쪽 View의 명시적 조인 관계 metadata |
|
||||
|
||||
## 7. 성공 기준
|
||||
|
||||
@@ -116,6 +148,8 @@ View comment에 기록한다.
|
||||
- 원격 직접 조회가 선사 8건과 실적 144건을 반환한다.
|
||||
- 로컬 View 3개가 `VALID` 상태다.
|
||||
- 최신 View가 8건을 반환하고 `GREEN`, `AMBER`, `RED`가 모두 존재한다.
|
||||
- `CARRIER_%` 접근 그룹 8개와 직원-그룹 구성원 8건이 존재한다.
|
||||
- `HMM_CARRIER_ASSIGNMENTS_V`와 `HMM_RDS_CARRIER_LATEST_V`의 조인이 8건을 반환한다.
|
||||
- Credential password가 SQL 파일, Git diff, 화면 출력에 남지 않는다.
|
||||
|
||||
## 8. 실패 시 판별
|
||||
@@ -132,6 +166,7 @@ View comment에 기록한다.
|
||||
|
||||
## 9. 제외 범위
|
||||
|
||||
- 이번 단계에서는 ADB 직원과 선사의 담당 배정 테이블 및 VPD 정책을 만들지 않는다.
|
||||
- 별도 직원-선사 담당 테이블은 만들지 않고 기존 접근 그룹 객체를 재사용한다.
|
||||
- 선사별 VPD 정책 적용은 후속 단계에서 수행한다.
|
||||
- Select AI profile과 MCP tool 등록은 로컬 View 검증 후 후속 단계에서 수행한다.
|
||||
- 실제 실행은 녹화를 진행하는 사용자가 SQL Worksheet에서 수행한다.
|
||||
|
||||
209
sql/adb/81_hmm_carrier_access_groups.sql
Normal file
209
sql/adb/81_hmm_carrier_access_groups.sql
Normal file
@@ -0,0 +1,209 @@
|
||||
-- ============================================================
|
||||
-- HMM carrier assignments using existing access-group tables.
|
||||
--
|
||||
-- Existing tables:
|
||||
-- HMM_HR_EMPLOYEES
|
||||
-- HMM_ACCESS_GROUPS
|
||||
-- HMM_ACCESS_GROUP_MEMBERS
|
||||
--
|
||||
-- No new assignment table is created.
|
||||
-- Korean values are reconstructed from UTF-8 base64 so SQLcl
|
||||
-- cannot corrupt the literals.
|
||||
-- Redmine: #730
|
||||
-- ============================================================
|
||||
|
||||
WHENEVER SQLERROR EXIT SQL.SQLCODE
|
||||
SET DEFINE OFF
|
||||
SET FEEDBACK ON
|
||||
SET SERVEROUTPUT ON
|
||||
|
||||
MERGE INTO hmm_access_groups dst
|
||||
USING (
|
||||
SELECT
|
||||
base.max_group_id + carrier.seq_no AS group_id,
|
||||
'CARRIER_' || carrier.carrier_code AS group_code,
|
||||
carrier.carrier_code || ' ' ||
|
||||
utl_i18n.raw_to_char(
|
||||
utl_encode.base64_decode(
|
||||
utl_raw.cast_to_raw('7ISg7IKsIOuLtOuLuSDqt7jro7k=')
|
||||
),
|
||||
'AL32UTF8'
|
||||
) AS group_name,
|
||||
utl_i18n.raw_to_char(
|
||||
utl_encode.base64_decode(
|
||||
utl_raw.cast_to_raw(
|
||||
'642w66qo7JqpIOyEoOyCrCDsoJHqt7wg67CPIOuLtOuLueyekCDqt7jro7k='
|
||||
)
|
||||
),
|
||||
'AL32UTF8'
|
||||
) || ' (' || carrier.carrier_code || ')' AS description
|
||||
FROM (
|
||||
SELECT 1 seq_no, 'C001' carrier_code FROM dual
|
||||
UNION ALL SELECT 2, 'C002' FROM dual
|
||||
UNION ALL SELECT 3, 'C003' FROM dual
|
||||
UNION ALL SELECT 4, 'C004' FROM dual
|
||||
UNION ALL SELECT 5, 'C005' FROM dual
|
||||
UNION ALL SELECT 6, 'C006' FROM dual
|
||||
UNION ALL SELECT 7, 'C007' FROM dual
|
||||
UNION ALL SELECT 8, 'C008' FROM dual
|
||||
) carrier
|
||||
CROSS JOIN (
|
||||
SELECT NVL(MAX(group_id), 0) max_group_id
|
||||
FROM hmm_access_groups
|
||||
) base
|
||||
) src
|
||||
ON (dst.group_code = src.group_code)
|
||||
WHEN MATCHED THEN UPDATE SET
|
||||
dst.group_name = src.group_name,
|
||||
dst.description = src.description,
|
||||
dst.active_yn = 'Y',
|
||||
dst.updated_at = SYSTIMESTAMP
|
||||
WHEN NOT MATCHED THEN INSERT (
|
||||
group_id,
|
||||
group_code,
|
||||
group_name,
|
||||
description,
|
||||
active_yn,
|
||||
created_at,
|
||||
updated_at
|
||||
) VALUES (
|
||||
src.group_id,
|
||||
src.group_code,
|
||||
src.group_name,
|
||||
src.description,
|
||||
'Y',
|
||||
SYSTIMESTAMP,
|
||||
SYSTIMESTAMP
|
||||
);
|
||||
|
||||
MERGE INTO hmm_access_group_members dst
|
||||
USING (
|
||||
SELECT
|
||||
access_group.group_id,
|
||||
employee.employee_id
|
||||
FROM (
|
||||
SELECT 'E1002' employee_code, 'CARRIER_C001' group_code FROM dual
|
||||
UNION ALL SELECT 'E1002', 'CARRIER_C002' FROM dual
|
||||
UNION ALL SELECT 'E1003', 'CARRIER_C003' FROM dual
|
||||
UNION ALL SELECT 'E1004', 'CARRIER_C004' FROM dual
|
||||
UNION ALL SELECT 'E1005', 'CARRIER_C005' FROM dual
|
||||
UNION ALL SELECT 'E1006', 'CARRIER_C006' FROM dual
|
||||
UNION ALL SELECT 'E1006', 'CARRIER_C007' FROM dual
|
||||
UNION ALL SELECT 'E1007', 'CARRIER_C008' FROM dual
|
||||
) assignment
|
||||
JOIN hmm_hr_employees employee
|
||||
ON employee.employee_code = assignment.employee_code
|
||||
AND employee.employment_status = 'ACTIVE'
|
||||
JOIN hmm_access_groups access_group
|
||||
ON access_group.group_code = assignment.group_code
|
||||
AND access_group.active_yn = 'Y'
|
||||
) src
|
||||
ON (
|
||||
dst.group_id = src.group_id
|
||||
AND dst.employee_id = src.employee_id
|
||||
)
|
||||
WHEN NOT MATCHED THEN INSERT (
|
||||
group_id,
|
||||
employee_id,
|
||||
created_at
|
||||
) VALUES (
|
||||
src.group_id,
|
||||
src.employee_id,
|
||||
SYSTIMESTAMP
|
||||
);
|
||||
|
||||
CREATE OR REPLACE VIEW hmm_carrier_assignments_v AS
|
||||
SELECT
|
||||
employee.employee_id,
|
||||
employee.employee_code,
|
||||
employee.full_name AS employee_name,
|
||||
employee.job_title,
|
||||
employee.team_id,
|
||||
employee.manager_employee_id,
|
||||
manager.employee_code AS manager_employee_code,
|
||||
manager.full_name AS manager_name,
|
||||
SUBSTR(access_group.group_code, LENGTH('CARRIER_') + 1) AS carrier_code,
|
||||
access_group.group_code,
|
||||
access_group.group_name
|
||||
FROM hmm_access_group_members membership
|
||||
JOIN hmm_access_groups access_group
|
||||
ON access_group.group_id = membership.group_id
|
||||
AND access_group.active_yn = 'Y'
|
||||
JOIN hmm_hr_employees employee
|
||||
ON employee.employee_id = membership.employee_id
|
||||
AND employee.employment_status = 'ACTIVE'
|
||||
LEFT JOIN hmm_hr_employees manager
|
||||
ON manager.employee_id = employee.manager_employee_id
|
||||
WHERE access_group.group_code LIKE 'CARRIER_C%';
|
||||
|
||||
COMMENT ON TABLE hmm_carrier_assignments_v IS
|
||||
'ADB employee-to-carrier assignments from HMM_HR_EMPLOYEES, HMM_ACCESS_GROUPS, and HMM_ACCESS_GROUP_MEMBERS. Join relationship: HMM_CARRIER_ASSIGNMENTS_V.CARRIER_CODE joins HMM_RDS_CARRIERS_V.CARRIER_CODE, HMM_RDS_CARRIER_PERF_V.CARRIER_CODE, and HMM_RDS_CARRIER_LATEST_V.CARRIER_CODE.';
|
||||
COMMENT ON COLUMN hmm_carrier_assignments_v.EMPLOYEE_CODE IS
|
||||
'HMM employee code sourced from HMM_HR_EMPLOYEES.EMPLOYEE_CODE. Example: E1002.';
|
||||
COMMENT ON COLUMN hmm_carrier_assignments_v.MANAGER_EMPLOYEE_CODE IS
|
||||
'Direct manager employee code sourced from HMM_HR_EMPLOYEES. Use E1001 to identify the HMM demo manager team.';
|
||||
COMMENT ON COLUMN hmm_carrier_assignments_v.CARRIER_CODE IS
|
||||
'Join Key and Foreign Key to HMM_RDS_CARRIERS_V(CARRIER_CODE), HMM_RDS_CARRIER_PERF_V(CARRIER_CODE), and HMM_RDS_CARRIER_LATEST_V(CARRIER_CODE).';
|
||||
COMMENT ON COLUMN hmm_carrier_assignments_v.GROUP_CODE IS
|
||||
'Existing access-group code in the form CARRIER_C001.';
|
||||
|
||||
COMMIT;
|
||||
|
||||
DECLARE
|
||||
v_group_count PLS_INTEGER;
|
||||
v_member_count PLS_INTEGER;
|
||||
v_assignment_count PLS_INTEGER;
|
||||
v_federated_count PLS_INTEGER;
|
||||
BEGIN
|
||||
SELECT COUNT(*)
|
||||
INTO v_group_count
|
||||
FROM hmm_access_groups
|
||||
WHERE group_code BETWEEN 'CARRIER_C001' AND 'CARRIER_C008'
|
||||
AND active_yn = 'Y';
|
||||
|
||||
SELECT COUNT(*)
|
||||
INTO v_member_count
|
||||
FROM hmm_access_group_members membership
|
||||
JOIN hmm_access_groups access_group
|
||||
ON access_group.group_id = membership.group_id
|
||||
WHERE access_group.group_code BETWEEN 'CARRIER_C001' AND 'CARRIER_C008';
|
||||
|
||||
SELECT COUNT(*)
|
||||
INTO v_assignment_count
|
||||
FROM hmm_carrier_assignments_v;
|
||||
|
||||
SELECT COUNT(*)
|
||||
INTO v_federated_count
|
||||
FROM hmm_carrier_assignments_v assignment
|
||||
JOIN hmm_rds_carrier_latest_v performance
|
||||
ON performance.carrier_code = assignment.carrier_code;
|
||||
|
||||
IF v_group_count != 8
|
||||
OR v_member_count != 8
|
||||
OR v_assignment_count != 8
|
||||
OR v_federated_count != 8 THEN
|
||||
RAISE_APPLICATION_ERROR(
|
||||
-20081,
|
||||
'Expected group/member/assignment/federated counts 8/8/8/8; found '
|
||||
|| v_group_count || '/'
|
||||
|| v_member_count || '/'
|
||||
|| v_assignment_count || '/'
|
||||
|| v_federated_count
|
||||
);
|
||||
END IF;
|
||||
END;
|
||||
/
|
||||
|
||||
SELECT
|
||||
assignment.employee_code,
|
||||
assignment.employee_name,
|
||||
assignment.manager_employee_code,
|
||||
assignment.carrier_code,
|
||||
performance.carrier_name,
|
||||
performance.performance_month,
|
||||
performance.revenue_usd,
|
||||
performance.risk_level
|
||||
FROM hmm_carrier_assignments_v assignment
|
||||
JOIN hmm_rds_carrier_latest_v performance
|
||||
ON performance.carrier_code = assignment.carrier_code
|
||||
ORDER BY assignment.employee_code, assignment.carrier_code;
|
||||
67
sql/adb/82_hmm_federation_relationship_comments.sql
Normal file
67
sql/adb/82_hmm_federation_relationship_comments.sql
Normal file
@@ -0,0 +1,67 @@
|
||||
-- ============================================================
|
||||
-- Explicit Select AI relationship metadata for ADB + RDS Views.
|
||||
-- Redmine: #730
|
||||
-- ============================================================
|
||||
|
||||
WHENEVER SQLERROR EXIT SQL.SQLCODE
|
||||
SET DEFINE OFF
|
||||
SET FEEDBACK ON
|
||||
|
||||
COMMENT ON TABLE hmm_carrier_assignments_v IS
|
||||
'ADB employee-to-carrier assignments from HMM_HR_EMPLOYEES, HMM_ACCESS_GROUPS, and HMM_ACCESS_GROUP_MEMBERS. Join relationship: HMM_CARRIER_ASSIGNMENTS_V.CARRIER_CODE joins HMM_RDS_CARRIERS_V.CARRIER_CODE, HMM_RDS_CARRIER_PERF_V.CARRIER_CODE, and HMM_RDS_CARRIER_LATEST_V.CARRIER_CODE.';
|
||||
|
||||
COMMENT ON COLUMN hmm_carrier_assignments_v.EMPLOYEE_CODE IS
|
||||
'HMM employee code sourced from HMM_HR_EMPLOYEES.EMPLOYEE_CODE. Example: E1002.';
|
||||
|
||||
COMMENT ON COLUMN hmm_carrier_assignments_v.MANAGER_EMPLOYEE_CODE IS
|
||||
'Direct manager employee code sourced from HMM_HR_EMPLOYEES. Use E1001 to identify the HMM demo manager team.';
|
||||
|
||||
COMMENT ON COLUMN hmm_carrier_assignments_v.CARRIER_CODE IS
|
||||
'Join Key and Foreign Key to HMM_RDS_CARRIERS_V(CARRIER_CODE), HMM_RDS_CARRIER_PERF_V(CARRIER_CODE), and HMM_RDS_CARRIER_LATEST_V(CARRIER_CODE).';
|
||||
|
||||
COMMENT ON TABLE hmm_rds_carriers_v IS
|
||||
'PostgreSQL fictional carrier master exposed through HMM_RDS_PG_LINK. Primary Key: CARRIER_CODE. Join relationship: HMM_RDS_CARRIERS_V.CARRIER_CODE joins HMM_CARRIER_ASSIGNMENTS_V.CARRIER_CODE and HMM_RDS_CARRIER_PERF_V.CARRIER_CODE.';
|
||||
|
||||
COMMENT ON COLUMN hmm_rds_carriers_v.CARRIER_CODE IS
|
||||
'Primary Key. Join Key to HMM_CARRIER_ASSIGNMENTS_V(CARRIER_CODE), HMM_RDS_CARRIER_PERF_V(CARRIER_CODE), and HMM_RDS_CARRIER_LATEST_V(CARRIER_CODE).';
|
||||
|
||||
COMMENT ON TABLE hmm_rds_carrier_perf_v IS
|
||||
'PostgreSQL monthly carrier KPI exposed through HMM_RDS_PG_LINK. Composite Primary Key: CARRIER_CODE and PERFORMANCE_MONTH. Foreign Key: CARRIER_CODE references HMM_RDS_CARRIERS_V(CARRIER_CODE). Join relationship: CARRIER_CODE joins HMM_CARRIER_ASSIGNMENTS_V.CARRIER_CODE.';
|
||||
|
||||
COMMENT ON COLUMN hmm_rds_carrier_perf_v.CARRIER_CODE IS
|
||||
'Foreign Key to HMM_RDS_CARRIERS_V(CARRIER_CODE). Join Key to HMM_CARRIER_ASSIGNMENTS_V(CARRIER_CODE).';
|
||||
|
||||
COMMENT ON COLUMN hmm_rds_carrier_perf_v.PERFORMANCE_MONTH IS
|
||||
'Part of the composite Primary Key with CARRIER_CODE. First calendar day of the KPI month.';
|
||||
|
||||
COMMENT ON TABLE hmm_rds_carrier_latest_v IS
|
||||
'Latest PostgreSQL KPI for each fictional carrier exposed through HMM_RDS_PG_LINK. Primary Key: CARRIER_CODE. Join relationship: HMM_RDS_CARRIER_LATEST_V.CARRIER_CODE joins HMM_CARRIER_ASSIGNMENTS_V.CARRIER_CODE and HMM_RDS_CARRIERS_V.CARRIER_CODE.';
|
||||
|
||||
COMMENT ON COLUMN hmm_rds_carrier_latest_v.CARRIER_CODE IS
|
||||
'Primary Key. Join Key to HMM_CARRIER_ASSIGNMENTS_V(CARRIER_CODE) and HMM_RDS_CARRIERS_V(CARRIER_CODE).';
|
||||
|
||||
SELECT table_name, comments
|
||||
FROM user_tab_comments
|
||||
WHERE table_name IN (
|
||||
'HMM_CARRIER_ASSIGNMENTS_V',
|
||||
'HMM_RDS_CARRIERS_V',
|
||||
'HMM_RDS_CARRIER_PERF_V',
|
||||
'HMM_RDS_CARRIER_LATEST_V'
|
||||
)
|
||||
ORDER BY table_name;
|
||||
|
||||
SELECT table_name, column_name, comments
|
||||
FROM user_col_comments
|
||||
WHERE table_name IN (
|
||||
'HMM_CARRIER_ASSIGNMENTS_V',
|
||||
'HMM_RDS_CARRIERS_V',
|
||||
'HMM_RDS_CARRIER_PERF_V',
|
||||
'HMM_RDS_CARRIER_LATEST_V'
|
||||
)
|
||||
AND column_name IN (
|
||||
'EMPLOYEE_CODE',
|
||||
'MANAGER_EMPLOYEE_CODE',
|
||||
'CARRIER_CODE',
|
||||
'PERFORMANCE_MONTH'
|
||||
)
|
||||
ORDER BY table_name, column_name;
|
||||
Reference in New Issue
Block a user