> ## Documentation Index
> Fetch the complete documentation index at: https://docs.sifi.life/llms.txt
> Use this file to discover all available pages before exploring further.

# SQL에서 PII 컬럼 사용 추적

> 이 문서는 **[Unity Catalog](/training/07-unity-catalog/overview)** 섹션의 일부입니다.

> **고객 질문**: "SQL 작성 시 개인정보 컬럼을 사용했는지 익명 컬럼을 사용했는지 자동으로 알 수 있는 기능이 있나요?"

***

## 짧은 답변

**단일 함수로 자동 판별하는 기능은 없습니다.** 하지만 Unity Catalog의 **태그 + Information Schema + 컬럼 리니지**를 조합하면 구현할 수 있습니다.

***

## Step 1: 컬럼에 PII 태그 부착

먼저 어떤 컬럼이 개인정보인지 **태그로 분류**합니다.

```sql theme={null}
-- 개인정보 컬럼
ALTER TABLE catalog.schema.customers 
  ALTER COLUMN 이름 SET TAGS ('pii' = 'true', 'pii_type' = 'name');
ALTER TABLE catalog.schema.customers 
  ALTER COLUMN 전화번호 SET TAGS ('pii' = 'true', 'pii_type' = 'phone');
ALTER TABLE catalog.schema.customers 
  ALTER COLUMN 주민번호 SET TAGS ('pii' = 'true', 'pii_type' = 'ssn');

-- 익명/일반 컬럼
ALTER TABLE catalog.schema.customers 
  ALTER COLUMN 지역코드 SET TAGS ('pii' = 'false');
ALTER TABLE catalog.schema.customers 
  ALTER COLUMN 가입년월 SET TAGS ('pii' = 'false');
```

### 대량 태깅 자동화

테이블이 많을 경우 Python으로 자동화합니다.

```python theme={null}
from databricks.sdk import WorkspaceClient

w = WorkspaceClient()

# PII 컬럼 목록 정의
pii_columns = {
    "catalog.schema.customers": {
        "이름": "name", "전화번호": "phone", "주민번호": "ssn",
        "이메일": "email", "주소": "address"
    },
    "catalog.schema.orders": {
        "배송주소": "address", "연락처": "phone"
    }
}

for table, columns in pii_columns.items():
    for col, pii_type in columns.items():
        w.statement_execution.execute_statement(
            warehouse_id="<warehouse_id>",
            statement=f"ALTER TABLE {table} ALTER COLUMN {col} SET TAGS ('pii' = 'true', 'pii_type' = '{pii_type}')"
        )
```

***

## Step 2: 특정 테이블의 PII 컬럼 조회

```sql theme={null}
-- 테이블의 컬럼별 PII 여부 확인
SELECT 
  column_name,
  tag_value AS is_pii
FROM system.information_schema.column_tags
WHERE catalog_name = 'catalog'
  AND schema_name = 'schema'
  AND table_name = 'customers'
  AND tag_name = 'pii'
ORDER BY column_name;
```

| column\_name | is\_pii |
| ------------ | ------- |
| 가입년월         | false   |
| 이름           | true    |
| 전화번호         | true    |
| 주민번호         | true    |
| 지역코드         | false   |

***

## Step 3: SQL에서 사용된 PII 컬럼 자동 추적

고객이 요청한 시나리오를 구현합니다.

```sql theme={null}
-- 고객이 이 쿼리를 실행했다고 가정
SELECT func(a), func(b)
FROM (
    SELECT 이름 AS a, 지역코드 AS b
    FROM catalog.schema.customers
);
```

### 방법 A: 컬럼 리니지 + 태그 조인

쿼리 실행 후 `system.access.column_lineage`에서 사용된 소스 컬럼을 추출하고, 태그와 조인합니다.

```sql theme={null}
-- 최근 쿼리에서 사용된 PII 컬럼 확인
SELECT 
  cl.source_table_full_name,
  cl.source_column_name,
  COALESCE(ct.tag_value, 'untagged') AS pii_status
FROM system.access.column_lineage cl
LEFT JOIN system.information_schema.column_tags ct
  ON cl.source_table_catalog = ct.catalog_name
  AND cl.source_table_schema = ct.schema_name
  AND cl.source_table_name = ct.table_name
  AND cl.source_column_name = ct.column_name
  AND ct.tag_name = 'pii'
WHERE cl.source_table_full_name = 'catalog.schema.customers'
  AND cl.event_time > current_timestamp() - INTERVAL 1 HOUR
ORDER BY cl.event_time DESC;
```

결과:

| source\_table\_full\_name | source\_column\_name | pii\_status |
| ------------------------- | -------------------- | ----------- |
| catalog.schema.customers  | 이름                   | **true**    |
| catalog.schema.customers  | 지역코드                 | false       |

→ **"이 SQL에서 사용한 컬럼 중 '이름'은 개인정보(PII), '지역코드'는 비개인정보입니다"**

### 방법 B: 사전 검증 함수 만들기

SQL 실행 **전에** PII 사용 여부를 확인하는 UC 함수를 만들 수 있습니다.

```sql theme={null}
CREATE OR REPLACE FUNCTION catalog.schema.check_pii_columns(
  table_name STRING,
  column_list ARRAY<STRING>
)
RETURNS TABLE (column_name STRING, is_pii STRING, pii_type STRING)
RETURN
  SELECT 
    c.value AS column_name,
    COALESCE(ct.tag_value, 'unknown') AS is_pii,
    COALESCE(ct2.tag_value, '-') AS pii_type
  FROM EXPLODE(column_list) AS c
  LEFT JOIN system.information_schema.column_tags ct
    ON ct.table_name = split(table_name, '.')[2]
    AND ct.column_name = c.value
    AND ct.tag_name = 'pii'
  LEFT JOIN system.information_schema.column_tags ct2
    ON ct2.table_name = split(table_name, '.')[2]
    AND ct2.column_name = c.value
    AND ct2.tag_name = 'pii_type';
```

```sql theme={null}
-- 사용 예시
SELECT * FROM catalog.schema.check_pii_columns(
  'catalog.schema.customers',
  ARRAY('이름', '지역코드', '전화번호')
);
```

| column\_name | is\_pii | pii\_type |
| ------------ | ------- | --------- |
| 이름           | true    | name      |
| 지역코드         | false   | -         |
| 전화번호         | true    | phone     |

***

## 추가 보호: Column Masking 자동 적용

PII 태그가 붙은 컬럼에 **자동 마스킹**을 적용하면, 권한 없는 사용자가 쿼리해도 원본 값이 노출되지 않습니다.

```sql theme={null}
-- PII 마스킹 함수
CREATE OR REPLACE FUNCTION catalog.schema.mask_pii(val STRING)
RETURNS STRING
RETURN CASE 
  WHEN is_member('pii_viewers') THEN val
  ELSE CONCAT(LEFT(val, 1), '***')
END;

-- 컬럼에 마스킹 적용
ALTER TABLE catalog.schema.customers 
  ALTER COLUMN 이름 SET MASK catalog.schema.mask_pii;
ALTER TABLE catalog.schema.customers 
  ALTER COLUMN 전화번호 SET MASK catalog.schema.mask_pii;
```

***

## 관련 문서

* [태그와 ABAC](/training/07-unity-catalog/tags) — 태그 부착 및 ABAC 정책
* [Column Masking](/training/07-unity-catalog/column-masks) — 동적 마스킹 패턴
* [데이터 리니지](/training/07-unity-catalog/data-lineage/overview) — 컬럼 레벨 추적
* [데이터 분류](/training/14-best-practices/enterprise-governance/data-classification) — 거버넌스 전략
