---
title: "브라우저에서 PostgreSQL을(를) SQL Server로 마이그레이션"
description: "PostgreSQL 데이터베이스를 SQL Server로 마이그레이션. pg_dump 파일을 같은 테이블, 키, 데이터의 스크립트로 바꾸고 모든 변경을 보고해요."
canonical: https://intosql.com/ko/postgresql-to-sql-server
last_updated: 2026-10-15
---

# 브라우저에서 PostgreSQL을(를) SQL Server로 마이그레이션

pg_dump나 pg_dumpall로 만든 .sql 또는 .sql.gz 일반 덤프를 놓으면, 같은 테이블, 키, 인덱스, 데이터를 담은 SQL Server 스크립트를 다운로드할 수 있어요. SQL Server이(가) 그대로 담을 수 없는 값과 옮기지 않는 객체는 모두 보고서에 나와요.

[PostgreSQL에서 SQL Server로 마이그레이션 가이드](https://intosql.com/docs/migrations/postgresql-to-sql-server)

[PostgreSQL에서 SQL Server로의 데이터 타입](https://intosql.com/docs/types/postgresql-to-sql-server)

## PostgreSQL에서 SQL Server로 바뀌는 점

각 행은 변환기가 적용하는 규칙이며, 규칙이 데이터를 바꿀 때 보고서에 쓰는 줄이 함께 나와요.

| PostgreSQL에서 | SQL Server에서 | 보고서 줄 |
| --- | --- | --- |
| boolean | bit |  |
| varchar(n), char(n), text | nvarchar(n), text는 nvarchar(max), 키에 쓰이고 모든 값이 들어가면 nvarchar(450) |  |
| text comparison | 정확히 비교(Latin1_General_100_BIN2), citext는 대소문자 무시(Latin1_General_100_CI_AS_SC) |  |
| numeric(p,s) past 38 digits; numeric without a precision | nvarchar, 값이 38자리에 들어가면 값에 맞춘 decimal(p,s) | `decimal_as_text` |
| money | decimal(19,2) | `type_replaced` |
| interval | PostgreSQL의 텍스트를 담은 nvarchar(100) | `type_replaced` |
| arrays (integer[], text[]...) | JSON 배열을 담은 nvarchar(max) | `type_replaced` |
| ranges, geometric types, tsvector, xml, hstore, PostGIS, composite and extension types | PostgreSQL의 텍스트를 담은 nvarchar(max) | `type_replaced` |
| json, jsonb | nvarchar(max) |  |
| timestamp | datetime2 |  |
| timestamp with time zone | UTC 기준 datetimeoffset |  |
| time with 24:00:00 in it | nvarchar(17) | `time_as_interval` |
| infinity, -infinity and BC dates | NULL | `date_out_of_range` |
| NaN and Infinity in numeric, real and double precision | NULL | `invalid_value_null` |
| NOT NULL columns with values that become NULL | NOT NULL 제거 | `not_null_relaxed` |
| enum types | 레이블 CHECK가 붙은 nvarchar |  |
| enum columns holding values outside their labels | 체크 제약 없는 nvarchar | `enum_check_skipped` |
| uuid, inet, cidr, macaddr | uniqueidentifier, 주소는 nvarchar |  |
| bytea | varbinary(max) |  |
| bit(n), bit varying | 1비트는 bit, 63비트까지는 bigint, 그 이상은 자릿수 텍스트 |  |
| oid, xid, cid | 음수가 아닌지 확인하는 CHECK가 붙은 bigint |  |
| serial, identity | IDENTITY, 가장 큰 id 다음부터 이어짐 |  |
| a second serial or identity column in a table | 일반 정수 | `counter_dropped` |
| sequences not owned by a column | 다음 값을 포함한 CREATE SEQUENCE ... AS bigint |  |
| generated columns | 계산 열, 원본에서 저장되면 PERSISTED |  |
| generated columns with functions SQL Server lacks | 값을 담은 일반 열 | `generated_not_translated` |
| defaults with functions SQL Server lacks, and defaults from a sequence | 기본값 없음 | `default_not_translated` |
| CHECK constraints | 변환해서 CREATE TABLE 안에 인라인으로 |  |
| CHECK constraints with functions SQL Server lacks | 만들지 않음 | `check_skipped` |
| CHECK ... NOT VALID | 만들지 않음 | `check_not_valid` |
| gin, gist, brin and hash indexes, partial and expression indexes, and indexes on text that doesn't fit a key | 만들지 않음 | `index_skipped` |
| foreign keys | 데이터 뒤에 WITH NOCHECK로 만들고, 고아 행은 경고와 함께 검사 |  |
| ON DELETE or ON UPDATE that cascades in a cycle or along a second path | NO ACTION | `foreign_key_action_dropped` |
| foreign keys to tables the dump doesn't create | 만들지 않음 | `foreign_key_skipped` |
| partitioned tables | 모든 파티션의 행을 담은 하나의 테이블 | `partitions_dropped` |
| views, functions, procedures, triggers, rules, policies, extensions and types | 보고서에 나열 | `not_converted_objects` |
| dumps without CREATE TABLE (--data-only) | 값으로 판단한 타입 | `no_schema` |
| expressions in INSERT values | NULL | `expression_value` |
| types IntoSQL doesn't know | nvarchar(max) | `unknown_type` |
| text that isn't valid in its encoding | 잘못된 바이트를 대체 문자로 | `invalid_utf8_replaced` |
| text decoded twice (Ã±) | 그대로 복사 | `mojibake_suspected` |

## 스크립트를 SQL Server에 불러오기

스크립트는 테이블을 만들고 행을 복사한 다음 키, 인덱스, 외래 키를 추가해요. 그래서 빨리 불러오고 첫 오류에서 멈춰요.

```shell
sqlcmd -b -f 65001 -S localhost -d mydb -i postgresql.sql_server.sql
```

외래 키는 WITH NOCHECK로 추가한 다음 검사해요. 어떤 행이 존재하지 않는 행을 가리키면, 중간에 실패하지 않고 어떤 제약인지 알려 주고 그 제약은 검사하지 않은 채로 남겨요.

큰 덤프는 서버와 같은 컴퓨터에서 sqlcmd를 실행하세요. 최대 1000행의 배치마다 따로 커밋하므로 트랜잭션 로그가 작게 유지돼요.

## 좋은 결과를 위한 PostgreSQL 덤프 방법

변환기는 덤프에 담긴 내용을 읽어요. 다음 옵션을 쓰면 더 많은 데이터가 덤프에 남아요:

- pg_dump의 기본값인 --format=plain은 SQL을 써요. custom 또는 directory 아카이브(-Fc, -Fd)는 데이터베이스 서버 없이 pg_restore -f dump.sql로 SQL이 돼요.
- --no-owner --no-privileges는 어차피 변환기가 건너뛰는 역할과 권한을 빼서 덤프가 작아져요.
- pg_dumpall은 모든 데이터베이스를 한 파일에 덤프해요. 각 데이터베이스의 테이블 이름에 그 데이터베이스 이름이 붙어서 충돌하지 않아요.

## 변환되지 않는 것

뷰, 구체화된 뷰, 함수, 프로시저, 트리거, 규칙, 행 보안 정책, 확장, 타입은 PostgreSQL의 자체 언어로 작성돼요. 보고서에 이름으로 나열되고 몰래 빠지는 일은 없으므로, SQL Server에 맞게 다시 작성할 수 있어요.

## PostgreSQL에서 SQL Server로 변환에 관한 질문

### 덤프가 업로드되나요?

아니요. 변환기는 브라우저에서 실행되고 디스크의 덤프를 조각조각 읽으므로, 덤프가 컴퓨터 밖으로 나가지 않아요. 데스크톱 앱과 명령줄도 컴퓨터에서 변환해요.

### 덤프는 얼마나 커도 되나요?

변환기는 덤프 전체를 메모리에 올리지 않아요. 파일을 범위별로 두 번 읽고, 읽는 대로 스크립트를 써요. 수 GB 덤프도 브라우저, 데스크톱 앱, 명령줄에서 변환돼요.

### pg_dump -Fc 아카이브도 읽나요?

직접은 읽지 않아요. custom 아카이브는 바이너리 형식이에요. pg_restore -f dump.sql dump.backup을 실행하면 서버에 연결하지 않고 변환기가 읽는 일반 SQL로 바뀌어요. 아카이브를 받으면 변환기가 이렇게 알려 줘요.

### 어떤 PostgreSQL 버전의 덤프를 읽나요?

PostgreSQL 10 이상에서 pg_dump와 pg_dumpall로 만든, COPY 또는 INSERT 행이 담긴 덤프예요. 모든 테스트 덤프는 PostgreSQL 13과 18에서 만들고 원본과 셀 단위로 비교해요.

### serial과 identity 값은 유지되나요?

네. 각 테이블의 serial 또는 identity 열은 IDENTITY 열이 되고, 모든 행은 id를 유지하며, 다음 id는 가장 큰 id 다음부터 이어져요. SQL Server은(는) 테이블마다 한 열만 번호를 매기므로 다른 열은 카운터 없이 값을 유지해요.

### 배열, enum 등 PostgreSQL 타입은 어떻게 되나요?

배열은 JSON 배열, boolean은 bit, uuid는 uniqueidentifier, 시간대가 있는 timestamp는 datetimeoffset이 돼요. 텍스트는 PostgreSQL처럼 정확히 비교하고, citext는 대소문자를 무시해요. 범위, 기하 타입, 복합 타입은 PostgreSQL의 텍스트를 유지해요.

### 함수, 트리거, 뷰는 어떻게 되나요?

데이터베이스마다 자체 언어로 작성하므로 변환하지 않고 보고서에 이름으로 나열해요.

### 스크립트는 어떤 SQL Server 버전에서 불러올 수 있나요?

SQL Server 2017부터 2025까지예요. 모든 버전에서 같은 스크립트를 불러올 수 있고, 문제가 생기면 첫 오류에서 멈춰요.

## PostgreSQL에서

- [PostgreSQL에서 PostgreSQL로](https://intosql.com/ko/postgresql-to-postgresql)
- [PostgreSQL에서 MySQL로](https://intosql.com/ko/postgresql-to-mysql)
- [PostgreSQL에서 MariaDB로](https://intosql.com/ko/postgresql-to-mariadb)
- [PostgreSQL에서 SQLite로](https://intosql.com/ko/postgresql-to-sqlite)
- [PostgreSQL에서 Oracle로](https://intosql.com/ko/postgresql-to-oracle)

## SQL Server로

- [MySQL에서 SQL Server로](https://intosql.com/ko/mysql-to-sql-server)
- [MariaDB에서 SQL Server로](https://intosql.com/ko/mariadb-to-sql-server)
- [SQL Server에서 SQL Server로](https://intosql.com/ko/sql-server-to-sql-server)
- [SQLite에서 SQL Server로](https://intosql.com/ko/sqlite-to-sql-server)
- [Oracle에서 SQL Server로](https://intosql.com/ko/oracle-to-sql-server)

## 가이드와 모든 조합

- [SQL Server에서 PostgreSQL로](https://intosql.com/ko/sql-server-to-postgresql)
- [PostgreSQL에서 SQL Server로 마이그레이션 가이드](https://intosql.com/docs/migrations/postgresql-to-sql-server)
- [PostgreSQL에서 SQL Server로의 데이터 타입](https://intosql.com/docs/types/postgresql-to-sql-server)
- [모든 데이터베이스 조합](https://intosql.com/ko/database-migration)
