

 Amazon Redshift는 패치 198부터 새 Python UDF 생성을 더 이상 지원하지 않습니다. 기존 Python UDF는 2026년 6월 30일까지 계속 작동합니다. 자세한 내용은 [블로그 게시물](https://aws.amazon.com/blogs/big-data/amazon-redshift-python-user-defined-functions-will-reach-end-of-support-after-june-30-2026/)을 참조하세요.

# 새 데이터 업데이트 및 삽입
<a name="t_updating-inserting-using-staging-tables-"></a>

MERGE 명령을 사용하여 기존 테이블에 새 데이터를 효율적으로 추가할 수 있습니다. 스테이징 테이블을 만든 다음 이 섹션에 설명된 방법 중 하나를 사용하여 스테이징 테이블에서 대상 테이블을 업데이트하여 병합 작업을 수행합니다. MERGE 명령에 대한 자세한 내용은 [MERGE](r_MERGE.md) 섹션을 참조하세요.

[병합 예](merge-examples.md)에서는 TICKIT 데이터 세트라고 하는 Amazon Redshift용 샘플 데이터 세트를 사용합니다. 필수 조건으로 [일반 데이터베이스 작업 시작하기](https://docs.aws.amazon.com/redshift/latest/gsg/database-tasks.html)에서 제공되는 지침에 따라 TICKIT 테이블과 데이터를 설정할 수 있습니다. 샘플 데이터 세트에 대한 자세한 내용은 [샘플 데이터베이스](https://docs.aws.amazon.com/redshift/latest/dg/c_sampledb.html)에서 확인할 수 있습니다.

## 병합 방법 1: 기존 행 교체
<a name="merge-method-replace-existing-rows"></a>

대상 테이블의 모든 열을 덮어쓰는 경우 병합을 수행하는 가장 빠른 방법은 기존 행을 바꾸는 것입니다. 이렇게 하면 업데이트할 행을 내부 조인을 사용하여 삭제하기 때문에 대상 테이블을 한 번만 스캔합니다. 행은 삭제된 후에 스테이징 테이블에서 단일 삽입 작업을 통해 새 행으로 교체됩니다.

다음이 모두 참인 경우, 이 방법을 사용하세요.
+ 대상 테이블과 스테이징 테이블에 동일한 열이 포함되어 있습니다.
+ 대상 테이블 열의 모든 데이터를 스테이징 테이블의 모든 열로 교체하려 합니다.
+ 병합에서 스테이징 테이블의 모든 열을 사용합니다.

이러한 기준 중 하나라도 해당되지 않는 경우 다음 섹션에 설명된 병합 방법 2: MERGE를 사용하지 않고 열 목록 지정을 사용하세요.

스테이징 테이블의 열 일부를 사용하지 않는 경우, 변경되지 않는 행을 WHERE 절을 이용해 배제하여 DELETE 및 INSERT 문을 필터링합니다. 하지만 스테이징 테이블의 열 대부분이 병합에 참여하지 않는다면 이 섹션 후반부에서 설명하는 것처럼 별도의 단계에서 UPDATE와 INSERT를 수행하는 것이 좋습니다.

## 병합 방법 2: MERGE를 사용하지 않고 열 목록 지정
<a name="merge-method-specify-column-list"></a>

전체 행을 덮어쓰는 대신 대상 테이블의 특정 열을 업데이트하려면 이 방법을 사용합니다. 이 방법은 추가 업데이트 단계가 필요하고 MERGE 명령을 사용하지 않기 때문에 이전 방법보다 시간이 오래 걸립니다. 다음 중 참인 것이 있다면 이 방법을 사용하세요.
+ 대상 테이블의 모든 열을 업데이트하는 것이 아닙니다.
+ 스테이징 테이블의 행 대부분이 업데이트에서 사용되지 않습니다.

**Topics**
+ [병합 방법 1: 기존 행 교체](#merge-method-replace-existing-rows)
+ [병합 방법 2: MERGE를 사용하지 않고 열 목록 지정](#merge-method-specify-column-list)
+ [임시 스테이징 테이블 생성](merge-create-staging-table.md)
+ [기존 행을 교체하여 병합 작업 수행](merge-replacing-existing-rows.md)
+ [MERGE 명령을 사용하지 않고 열 목록을 지정하여 병합 작업 수행](merge-specify-a-column-list.md)
+ [병합 예](merge-examples.md)

# 임시 스테이징 테이블 생성
<a name="merge-create-staging-table"></a>

*스테이징 테이블*은 업데이트와 삽입을 포함하여 *대상 테이블*을 변경하는 데 사용될 모든 데이터가 보관되는 임시 테이블입니다.

병합 작업에는 스테이징 테이블과 대상 테이블 간의 조인이 필요합니다. 조인 행을 배치하려면 스테이징 테이블의 분산 키를 대상 테이블의 분산 키와 동일한 열로 설정합니다. 예를 들어 대상 테이블이 외래 키 열을 분산 키로 사용하는 경우, 스테이징 테이블의 분산 키에 동일한 열을 사용하세요. [CREATE TABLE LIKE](r_CREATE_TABLE_NEW.md#create-table-like) 문을 사용하여 스테이징 테이블을 생성하는 경우, 스테이징 테이블은 상위 테이블에서 분산 키를 상속합니다. CREATE TABLE AS 문을 사용하는 경우에는 새 테이블이 분산 키를 상속하지 않습니다. 자세한 내용은 [쿼리 최적화를 위한 데이터 배포](t_Distributing_data.md) 섹션을 참조하세요.

분산 키가 기본 키와 동일하지 않고 병합 작업의 일환으로 분산 키가 업데이트되지 않는 경우, 분산 키 열에서 중복 조인 조건자를 추가하여 배치된 조인을 활성화합니다. 예: 

```
where target.primarykey = stage.primarykey 
and target.distkey = stage.distkey
```

쿼리가 배치된 조인을 사용할지 확인하려면 [EXPLAIN](r_EXPLAIN.md)과 함께 쿼리를 실행하고 모든 조인에서 DS\$1DIST\$1NONE을 확인합니다. 자세한 내용은 [쿼리 계획 평가](c_data_redistribution.md) 섹션을 참조하세요.

# 기존 행을 교체하여 병합 작업 수행
<a name="merge-replacing-existing-rows"></a>

해당 절차에 상세히 설명된 병합 작업을 실행할 때 모든 단계를 포함하되 단일 트랜잭션에서 임시 스테이징 테이블을 생성하거나 삭제할 때는 예외입니다. 임의 단계가 실패하면 트랜잭션이 롤백됩니다. 단일 트랜잭션을 사용하면 커밋의 수도 줄어들어 시간과 자원을 절약할 수 있습니다.

**기존 행을 교체하여 병합 작업을 수행하려면**

1. 다음 유사 코드에 나온 것처럼 스테이징 테이블을 생성한 다음 병합될 데이터로 테이블을 채웁니다.

   ```
   CREATE temp table stage (like target); 
   
   INSERT INTO stage 
   SELECT * FROM source 
   WHERE source.filter = 'filter_expression';
   ```

1.  MERGE를 사용하여 스테이징 테이블과 내부 조인을 수행하여 스테이징 테이블과 일치하는 대상 테이블의 행을 업데이트한 다음 스테이징 테이블과 일치하지 않는 나머지 모든 행을 대상 테이블에 삽입합니다.

    업데이트 및 삽입 작업은 하나의 MERGE 명령으로 실행하는 것이 좋습니다.

   ```
   MERGE INTO target 
   USING stage [optional alias] on (target.primary_key = stage.primary_key)
   WHEN MATCHED THEN 
   UPDATE SET col_name1 = stage.col_name1 , col_name2= stage.col_name2, col_name3 = {expr}
   WHEN NOT MATCHED THEN
   INSERT (col_name1 , col_name2, col_name3) VALUES (stage.col_name1, stage.col_name2, {expr});
   ```

1. 스테이징 테이블을 삭제합니다.

   ```
   DROP TABLE stage;
   ```

# MERGE 명령을 사용하지 않고 열 목록을 지정하여 병합 작업 수행
<a name="merge-specify-a-column-list"></a>

절차에 자세히 설명된 병합 작업을 실행할 때는 모든 단계를 단일 트랜잭션에 포함시키세요. 임의 단계가 실패하면 트랜잭션이 롤백됩니다. 단일 트랜잭션을 사용하면 커밋의 수도 줄어들어 시간과 자원을 절약할 수 있습니다.

**열 목록을 지정하여 병합 작업을 수행하려면**

1. 전체 작업을 단일 트랜잭션 블록에 넣습니다.

   ```
   BEGIN transaction;
   … 
   END transaction;
   ```

1. 다음 유사 코드에 나온 것처럼 스테이징 테이블을 생성한 다음 병합될 데이터로 테이블을 채웁니다.

   ```
   create temp table stage (like target); 
   insert into stage 
   select * from source 
   where source.filter = 'filter_expression';
   ```

1. 스테이징 테이블과의 내부 조인을 사용하여 대상 테이블을 업데이트합니다.
   + UPDATE 절에서 업데이트될 열을 명시적으로 나열합니다.
   + 스테이징 테이블과의 내부 조인을 수행합니다.
   + 분산 키가 기본 키와 다르고 분산 키가 업데이트되지 않는 경우, 분산 키에서 중복 조인을 추가합니다. 쿼리가 배치된 조인을 사용할지 확인하려면 [EXPLAIN](r_EXPLAIN.md)과 함께 쿼리를 실행하고 모든 조인에서 DS\$1DIST\$1NONE을 확인합니다. 자세한 내용은 [쿼리 계획 평가](c_data_redistribution.md) 섹션을 참조하세요.
   + 대상 테이블이 타임스탬프 기준으로 정렬된 경우 대상 테이블에서 범위 제한 스캔을 활용하기 위해 술어를 추가합니다. 자세한 내용은 [Amazon Redshift 쿼리 설계 모범 사례](c_designing-queries-best-practices.md) 섹션을 참조하세요.
   + 병합에서 사용하지 않는 행이 있는 경우, 변경할 행을 필터링하기 위해 절을 추가합니다. 예를 들어 하나 이상의 열에서 부등식 필터를 추가하여 변경되지 않은 행을 제외합니다.
   + 문제가 생기면 모든 것을 롤백할 수 있도록 업데이트 작업, 삭제 작업, 삽입 작업을 단일 트랜잭션 블록에 넣습니다.

    예: 

   ```
   begin transaction;
   
   update target 
   set col1 = stage.col1, 
   col2 = stage.col2, 
   col3 = 'expression' 
   from stage 
   where target.primarykey = stage.primarykey 
   and target.distkey = stage.distkey 
   and target.col3 > 'last_update_time' 
   and (target.col1 != stage.col1 
   or target.col2 != stage.col2 
   or target.col3 = 'filter_expression');
   ```

1. 대상 테이블과의 내부 조인을 사용하여 스테이징 테이블에서 필요 없는 행을 삭제합니다. 대상 테이블의 행 중에는 스테이징 테이블의 행과 이미 일치하는 행도 있고 이전 단계에서 업데이트된 행도 있습니다. 어느 경우건 이 행들은 삽입에 필요하지 않습니다.

   ```
   delete from stage 
   using target 
   where stage.primarykey = target.primarykey;
   ```

1. 스테이징 테이블에서 나머지 행을 삽입합니다. VALUES 절에 2단계에서 UPDATE 문에 사용한 것과 동일한 열 목록을 사용합니다.

   ```
   insert into target
   (select col1, col2, 'expression'
   from stage);
   
   end transaction;
   ```

1. 스테이징 테이블을 삭제합니다.

   ```
   drop table stage;
   ```

# 병합 예
<a name="merge-examples"></a>

다음 예는 병합을 수행하여 SALES 테이블을 업데이트합니다. 첫 번째 예는 대상 테이블에서 모든 행을 삭제한 다음 준비 열에서 삽입하는 보다 간단한 방법을 사용합니다. 두 번째 예는 대상 테이블의 선택된 열에서의 업데이트가 필요하므로 추가 업데이트 단계가 포함됩니다.

[병합 예](#merge-examples)에서는 TICKIT 데이터 세트라고 하는 Amazon Redshift용 샘플 데이터 세트를 사용합니다. 필수 조건으로 [일반 데이터베이스 작업 시작하기](https://docs.aws.amazon.com/redshift/latest/gsg/database-tasks.html) 가이드의 지침에 따라 TICKIT 테이블과 데이터를 설정할 수 있습니다. 샘플 데이터 세트에 대한 자세한 내용은 [샘플 데이터베이스](https://docs.aws.amazon.com/redshift/latest/dg/c_sampledb.html)에서 확인할 수 있습니다.

**데이터 원본 샘플 병합**

이 섹션의 예에는 업데이트와 삽입이 모두 포함된 샘플 데이터 원본이 필요합니다. 예를 위해 SALES 테이블의 데이터를 사용하는 SALES\$1UPDATE라는 이름의 샘플 테이블을 만듭니다. 12월 신규 영업 활동을 나타내는 무작위 데이터로 새 테이블을 채웁니다. 다음에 나오는 예에서는 SALES\$1UPDATE 샘플 테이블을 사용해 스테이징 테이블을 만듭니다.

```
-- Create a sample table as a copy of the SALES table.

create table tickit.sales_update as
select * from tickit.sales;

-- Change every fifth row to have updates.

update tickit.sales_update
set qtysold = qtysold*2,
pricepaid = pricepaid*0.8,
commission = commission*1.1
where saletime > '2008-11-30'
and mod(sellerid, 5) = 0;

-- Add some new rows to have inserts.
-- This example creates a duplicate of every fourth row.

insert into tickit.sales_update
select (salesid + 172456) as salesid, listid, sellerid, buyerid, eventid, dateid, qtysold, pricepaid, commission, getdate() as saletime
from tickit.sales_update
where saletime > '2008-11-30'
and mod(sellerid, 4) = 0;
```

**매칭 키를 기반으로 기존 행을 교체하는 병합 예**

다음 스크립트는 SALES\$1UPDATE 테이블을 사용해 12월 영업 활동의 새 데이터로 SALES 테이블에서 병합 작업을 수행합니다. 이 예제에서는 업데이트가 있는 SALES 테이블의 행을 바꿉니다. 이 예제에서는 판매 수량 및 가격 지불 열을 업데이트하지만 수수료 및 급여 시간은 변경하지 않습니다.

```
MERGE into tickit.sales 
USING tickit.sales_update sales_update  
on ( sales.salesid = sales_update.salesid
and sales.listid = sales_update.listid
and sales_update.saletime > '2008-11-30'
and (sales.qtysold != sales_update.qtysold 
or sales.pricepaid != sales_update.pricepaid))
WHEN MATCHED THEN
update SET qtysold = sales_update.qtysold,
pricepaid = sales_update.pricepaid
WHEN NOT MATCHED THEN 
INSERT (salesid, listid, sellerid, buyerid, eventid, dateid, qtysold , pricepaid, commission, saletime)
values (sales_update.salesid, sales_update.listid, sales_update.sellerid, sales_update.buyerid, sales_update.eventid, 
sales_update.dateid, sales_update.qtysold , sales_update.pricepaid, sales_update.commission, sales_update.saletime);

-- Drop the staging table.
drop table tickit.sales_update;

-- Test to see that commission and salestime were not impacted.
SELECT sales.salesid, sales.commission, sales.salestime, sales_update.commission, sales_update.salestime 
FROM tickit.sales 
INNER JOIN tickit.sales_update sales_update  
ON 
sales.salesid = sales_update.salesid
AND sales.listid = sales_update.listid
AND sales_update.saletime > '2008-11-30'
AND (sales.commission != sales_update.commission 
OR sales.salestime != sales_update.salestime);
```

**MERGE를 사용하지 않고 열 목록을 지정하는 병합 예**

다음 예는 병합 작업을 수행하여 12월 영업 활동의 새 데이터로 SALES를 업데이트합니다. 변경되지 않은 행과 함께 업데이트와 삽입이 모두 포함된 샘플 데이터가 필요합니다. 이 예에서는 QTYSOLD 및 PRICEPAID 열은 업데이트하되 COMMISSION과 SALETIME은 변경하지 않으려 합니다. 다음 스크립트는 SALES\$1UPDATE 테이블을 사용해 SALES 테이블에서 병합 작업을 수행합니다.

```
-- Create a staging table and populate it with rows from SALES_UPDATE for Dec
create temp table stagesales as select * from sales_update
where saletime > '2008-11-30';

-- Start a new transaction
begin transaction;

-- Update the target table using an inner join with the staging table
-- The join includes a redundant predicate to collocate on the distribution key –- A filter on saletime enables a range-restricted scan on SALES

update sales
set qtysold = stagesales.qtysold,
pricepaid = stagesales.pricepaid
from stagesales
where sales.salesid = stagesales.salesid
and sales.listid = stagesales.listid
and stagesales.saletime > '2008-11-30'
and (sales.qtysold != stagesales.qtysold 
or sales.pricepaid != stagesales.pricepaid);
 
-- Delete matching rows from the staging table 
-- using an inner join with the target table

delete from stagesales
using sales
where sales.salesid = stagesales.salesid
and sales.listid = stagesales.listid;

-- Insert the remaining rows from the staging table into the target table
insert into sales
select * from stagesales;

-- End transaction and commit
end transaction;

-- Drop the staging table
drop table stagesales;
```