본문으로 건너뛰기
IntoSQL 홈

PostgreSQL에서 SQL Server로 변환

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

내 파일
sqlshop_2024_postgres.sql샘플 파일, 6.2kB
내 데이터베이스

18개 행 변환, 수정 2개, 거부 없음

보기

shop_2024_postgres.sql의 테이블PostgreSQL 18.6 덤프 · pg_dump(으)로 작성됨 · utf8mb4

  • customers8개 행1
    8개 열
    idint not null
    namenvarchar(max) not null
    emailnvarchar(450) not null
    countrynvarchar(2) not null
    is_activebit not null
    tagsnvarchar(max) not null
    signed_update
    created_atdatetimeoffset(6) not null
  • orders10개 행1
    10개 열
    idint not null
    customer_idint not null
    statusnvarchar(9) not null
    totaldecimal(10,2) not null
    itemssmallint not null
    ordered_atdatetime2(6) not null
    shipped_atdatetime2(6)
    notenvarchar(max)
    detailsnvarchar(max)
    deliverynvarchar(100)

변환되지 않음

  • 뷰 paid_orders

데이터베이스마다 이 객체를 자체 언어로 작성해요. SQL Server에 맞게 다시 작성하세요.

-- Written by IntoSQL from a PostgreSQL dump. Load it with: sqlcmd -b -f 65001 -d <database> -i <file>
SET NOCOUNT ON;
SET ANSI_NULLS ON;
SET QUOTED_IDENTIFIER ON;
SET ANSI_PADDING ON;
SET ANSI_WARNINGS ON;
SET ARITHABORT ON;
SET CONCAT_NULL_YIELDS_NULL ON;
SET NUMERIC_ROUNDABORT OFF;
GO

CREATE TABLE [dbo].[customers] (
    [id] int IDENTITY(1001, 1) NOT NULL,
    [name] nvarchar(max) COLLATE Latin1_General_100_BIN2 NOT NULL,
    [email] nvarchar(450) COLLATE Latin1_General_100_BIN2 NOT NULL,
    [country] nvarchar(2) COLLATE Latin1_General_100_BIN2 DEFAULT N'US' NOT NULL,
    [is_active] bit DEFAULT 1 NOT NULL,
    [tags] nvarchar(max) COLLATE Latin1_General_100_BIN2 NOT NULL,
    [signed_up] date NULL,
    [created_at] datetimeoffset(6) DEFAULT SYSDATETIMEOFFSET() NOT NULL,
    CONSTRAINT [PK_customers] PRIMARY KEY ([id])
);
GO

CREATE TABLE [dbo].[orders] (
    [id] int IDENTITY(5001, 1) NOT NULL,
    [customer_id] int NOT NULL,
    [status] nvarchar(9) COLLATE Latin1_General_100_BIN2 DEFAULT N'pending' NOT NULL,
    [total] decimal(10,2) NOT NULL,
    [items] smallint DEFAULT 1 NOT NULL,
    [ordered_at] datetime2(6) NOT NULL,
    [shipped_at] datetime2(6) NULL,
    [note] nvarchar(max) COLLATE Latin1_General_100_BIN2 NULL,
    [details] nvarchar(max) COLLATE Latin1_General_100_BIN2 NULL,
    [delivery] nvarchar(100) COLLATE Latin1_General_100_BIN2 NULL,
    CONSTRAINT [CK_orders_status] CHECK ([status] IN (N'pending', N'paid', N'shipped', N'cancelled')),
    CONSTRAINT [orders_total_check] CHECK ([total] >= (0)),
    CONSTRAINT [PK_orders] PRIMARY KEY ([id])
);
GO

SET IDENTITY_INSERT [dbo].[customers] ON;
INSERT INTO [dbo].[customers] ([id], [name], [email], [country], [is_active], [tags], [signed_up], [created_at]) VALUES
(1,N'Ana Martínez',N'ana@example.com',N'MX',1,N'["vip"]','2023-01-15','2023-01-15 10:24:00+00:00'),
(2,N'Zoë Müller',N'zoe@example.de',N'DE',1,N'[]','2023-02-03','2023-02-03 08:11:42+00:00'),
(3,N'José Peña',N'jose@example.es',N'ES',0,N'["wholesale","late payer"]','2023-03-21','2023-03-21 19:05:17+00:00'),
(4,N'李雷',N'lilei@example.cn',N'CN',1,N'[]','2023-05-09','2023-05-09 02:40:00+00:00'),
(5,N'Noah O''Brien',N'noah@example.ie',N'IE',1,N'[]',NULL,'2023-06-30 14:00:00+00:00'),
(6,N'Amélie Laurent',N'amelie@example.fr',N'FR',1,N'["vip"]','2024-01-02','2024-01-02 09:30:00+00:00'),
(7,N'Ravi Patel',N'ravi@example.in',N'IN',0,N'[]','2024-02-29','2024-02-29 23:59:59+00:00'),
(8,N'Sofia Rossi 🌻',N'sofia@example.it',N'IT',1,N'[]','2024-04-12','2024-04-12 12:12:12+00:00');
SET IDENTITY_INSERT [dbo].[customers] OFF;
GO
SET IDENTITY_INSERT [dbo].[orders] ON;
INSERT INTO [dbo].[orders] ([id], [customer_id], [status], [total], [items], [ordered_at], [shipped_at], [note], [details], [delivery]) VALUES
(1,1,N'shipped',129.90,3,'2024-03-01 10:00:00','2024-03-02 16:30:00',NULL,N'{"gift": false}',N'1 day 06:30:00'),
(2,2,N'paid',54.00,1,'2024-03-02 11:15:00',NULL,N'Gift wrap 🎁',N'{"gift": true, "wrap": "red"}',NULL),
(3,1,N'cancelled',12.50,1,'2024-03-03 09:45:00',NULL,N'Customer changed their mind',NULL,NULL),
(4,4,N'shipped',980.00,12,'2024-03-05 02:10:00','2024-03-07 08:00:00',N'请小心轻放',N'{"fragile": true}',N'2 days 05:50:00'),
(5,5,N'pending',45.75,2,'2024-03-08 17:20:00',NULL,N'Leave at the door; ring twice',NULL,NULL),
(6,6,N'shipped',310.40,5,'2024-03-10 13:00:00','2024-03-11 09:00:00',N'Fragile: "glass"',N'{"fragile": true}',N'20:00:00'),
(7,8,N'paid',76.20,2,'2024-03-11 18:45:00',NULL,NULL,NULL,NULL),
(8,2,N'shipped',19.99,1,'2024-03-12 08:00:00',NULL,N'Shipped date set to infinity by an old import',NULL,NULL),
(9,3,N'shipped',64.00,2,'2024-03-14 15:30:00','2024-03-15 10:00:00',N'Two parcels',N'{"parcels": [1, 2]}',N'18:30:00'),
(10,7,N'paid',1499.00,1,'2024-03-15 21:05:00',NULL,N'C:\Users\ravi\invoice.pdf',NULL,NULL);
SET IDENTITY_INSERT [dbo].[orders] OFF;
GO

-- Indexes, foreign keys, counters and triggers, after the rows.
CREATE UNIQUE INDEX [customers_email_key] ON [dbo].[customers] ([email]);
CREATE INDEX [idx_orders_customer] ON [dbo].[orders] ([customer_id]);
CREATE INDEX [idx_orders_status_date] ON [dbo].[orders] ([status], [ordered_at]);
ALTER TABLE [dbo].[orders] WITH NOCHECK ADD CONSTRAINT [orders_customer_id_fkey] FOREIGN KEY ([customer_id]) REFERENCES [dbo].[customers] ([id]);
BEGIN TRY ALTER TABLE [dbo].[orders] WITH CHECK CHECK CONSTRAINT [orders_customer_id_fkey]; END TRY BEGIN CATCH PRINT N'Foreign key ' + N'[orders_customer_id_fkey]' + N' has rows without a parent: it stays unchecked, and new rows are checked.'; END CATCH;
DECLARE @next decimal(38,0) = (SELECT MAX([id]) FROM [dbo].[customers]); IF @next IS NOT NULL BEGIN IF @next < 1000 SET @next = 1000; DBCC CHECKIDENT (N'[dbo].[customers]', RESEED, @next) WITH NO_INFOMSGS; END;
GO
EXEC sys.sp_addextendedproperty @name = N'MS_Description', @value = N'People who bought at least once', @level0type = N'SCHEMA', @level0name = N'dbo', @level1type = N'TABLE', @level1name = N'customers';
DECLARE @next decimal(38,0) = (SELECT MAX([id]) FROM [dbo].[orders]); IF @next IS NOT NULL BEGIN IF @next < 5000 SET @next = 5000; DBCC CHECKIDENT (N'[dbo].[orders]', RESEED, @next) WITH NO_INFOMSGS; END;
GO
GO

수정 사항

  1. customers의 "tags" 열은 SQL Server에 없는 text[](이)라서 같은 값을 담은 nvarchar(max)(으)로 만들었어요.
  2. orders의 "delivery" 열은 SQL Server에 없는 interval(이)라서 같은 값을 담은 nvarchar(100)(으)로 만들었어요.

확인 필요

  • 뷰, 트리거, 루틴, 이벤트 1개가 변환되지 않았어요. 보고서에 각각 나와 있어요. SQL Server에서 직접 다시 만드세요.
  • customers의 "tags" 열 기본값을 SQL Server용으로 쓸 수 없어(a value its type can't hold) 기본값 없이 만들었어요. 새 행에 필요하면 기본값을 직접 추가하세요.
  • orders의 인덱스 idx_orders_details은(는) SQL Server용으로 쓸 수 없는 식을 사용해서(an index on an expression) 만들지 않았어요. 쿼리에 필요하면 인덱스를 직접 만드세요.
  • orders의 "shipped_at" 열에 있는 1개 값은 infinity처럼 SQL Server이(가) 저장할 수 없는 날짜라서 NULL로 두었어요. SQL Server은(는) 1년부터 9999년까지만 저장하고 infinity는 없어요. 이 날짜가 중요하면 원본에서 바꾸세요.

파일은 이 컴퓨터에서 변환되고 업로드되지 않아요.

다른 샘플:

PostgreSQL에서 SQL Server로 바뀌는 점

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

  • boolean

    bit

    bit는 true를 1, false를 0으로 담아요.

  • varchar(n), char(n), text

    nvarchar(n), text는 nvarchar(max), 키에 쓰이고 모든 값이 들어가면 nvarchar(450)

    nvarchar는 모든 문자를 담아요. SQL Server는 nvarchar(max)를 인덱싱할 수 없어서 키에 있는 텍스트는 키에 맞는 크기로 정해요.

  • text comparison

    정확히 비교(Latin1_General_100_BIN2), citext는 대소문자 무시(Latin1_General_100_CI_AS_SC)

    SQL Server의 일반적인 콜레이션은 대소문자를 무시하지만 PostgreSQL의 텍스트는 그렇지 않아요. 그래서 열마다 비교 방식을 지정하고, 고유 키는 같은 행들을 구분해요.

  • numeric(p,s) past 38 digits; numeric without a precision

    nvarchar, 값이 38자리에 들어가면 값에 맞춘 decimal(p,s)

    SQL Server의 decimal은 38자리까지 담아요. 정밀도가 없는 numeric은 값이 들어가는 가장 좁은 decimal이 되고, 더 넓은 숫자는 모든 자릿수가 정확하도록 텍스트로 유지해요.

    보고서 줄: decimal_as_text

  • money

    decimal(19,2)

    SQL Server의 money는 PostgreSQL보다 작고 소수 4자리예요. decimal(19,2)는 서버 로캘이 붙인 통화 기호 없이 모든 금액을 담아요.

    보고서 줄: type_replaced

  • interval

    PostgreSQL의 텍스트를 담은 nvarchar(100)

    SQL Server에는 interval 타입이 없어요. 텍스트가 모든 부분을 유지해요.

    보고서 줄: type_replaced

  • arrays (integer[], text[]...)

    JSON 배열을 담은 nvarchar(max)

    SQL Server에는 배열이 없어요. JSON 배열은 모든 항목과 NULL을 유지하고 OPENJSON으로 읽을 수 있어요.

    보고서 줄: type_replaced

  • ranges, geometric types, tsvector, xml, hstore, PostGIS, composite and extension types

    PostgreSQL의 텍스트를 담은 nvarchar(max)

    SQL Server에는 같은 타입이 없어서 각 값은 PostgreSQL이 쓴 텍스트를 유지해요.

    보고서 줄: type_replaced

  • json, jsonb

    nvarchar(max)

    SQL Server의 JSON 함수는 텍스트에서 JSON을 읽어요.

  • timestamp

    datetime2

    timestamp without time zone은 datetime2처럼 시계에 표시된 시각이에요.

  • timestamp with time zone

    UTC 기준 datetimeoffset

    datetimeoffset은 시점을 유지해요. 각 값은 UTC로 쓰며, 덤프에 적힌 오프셋과 상관없이 같은 시점이에요.

  • time with 24:00:00 in it

    nvarchar(17)

    SQL Server의 time은 23:59:59.9999999에서 끝나서 24:00:00이 있는 열은 텍스트를 유지해요.

    보고서 줄: time_as_interval

  • infinity, -infinity and BC dates

    NULL

    SQL Server는 1년부터 9999년까지만 저장하고 infinity는 없어요. 이 값은 NULL이 되고 보고서에 개수가 나와요.

    보고서 줄: date_out_of_range

  • NaN and Infinity in numeric, real and double precision

    NULL

    SQL Server의 숫자에는 NaN이나 Infinity가 없어서 이 값은 NULL이 되고 보고서에 개수가 나와요.

    보고서 줄: invalid_value_null

  • NOT NULL columns with values that become NULL

    NOT NULL 제거

    값을 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

    uniqueidentifier는 SQL Server의 UUID예요. 주소는 텍스트로 유지해요.

  • bytea

    varbinary(max)

    바이트는 바이트 그대로 남아요.

  • bit(n), bit varying

    1비트는 bit, 63비트까지는 bigint, 그 이상은 자릿수 텍스트

    1비트는 예/아니요이고, 더 긴 비트 문자열은 비트가 만드는 숫자로 저장해요.

  • oid, xid, cid

    음수가 아닌지 확인하는 CHECK가 붙은 bigint

    bigint는 모든 값을 담아요.

  • serial, identity

    IDENTITY, 가장 큰 id 다음부터 이어짐

    복사된 id는 IDENTITY_INSERT로 불러오고, 카운터는 가장 큰 id와 시퀀스의 다음 값 중 더 큰 값 다음부터 이어져요.

  • a second serial or identity column in a table

    일반 정수

    SQL Server는 테이블마다 IDENTITY 열 하나만 번호를 매겨요. 다른 열은 카운터 없이 값을 유지해요.

    보고서 줄: counter_dropped

  • sequences not owned by a column

    다음 값을 포함한 CREATE SEQUENCE ... AS bigint

    SQL Server에도 같은 옵션의 시퀀스가 있어요. 각 시퀀스는 덤프가 멈춘 곳부터 이어져요.

  • generated columns

    계산 열, 원본에서 저장되면 PERSISTED

    SQL Server도 같은 두 가지 방식으로 계산해요.

  • generated columns with functions SQL Server lacks

    값을 담은 일반 열

    SQL Server용으로 쓸 수 없는 수식은 덤프의 값을 담은 일반 열로 남고 보고서에 한 줄 기록돼요.

    보고서 줄: generated_not_translated

  • defaults with functions SQL Server lacks, and defaults from a sequence

    기본값 없음

    SQL Server용으로 쓸 수 없는 기본값은 제외하고 보고해요.

    보고서 줄: default_not_translated

  • CHECK constraints

    변환해서 CREATE TABLE 안에 인라인으로

    인라인 체크 제약은 각 행을 불러올 때 검사해요.

  • CHECK constraints with functions SQL Server lacks

    만들지 않음

    SQL Server용으로 쓸 수 없는 체크 제약은 제외하고 보고해요.

    보고서 줄: check_skipped

  • CHECK ... NOT VALID

    만들지 않음

    PostgreSQL은 기존 행을 검사한 적이 없어서 그 행이 제약을 어길 수 있어요.

    보고서 줄: check_not_valid

  • gin, gist, brin and hash indexes, partial and expression indexes, and indexes on text that doesn't fit a key

    만들지 않음

    SQL Server는 식이 아닌 열을 인덱싱하고, nvarchar(max)는 인덱싱하지 않아요.

    보고서 줄: index_skipped

  • foreign keys

    데이터 뒤에 WITH NOCHECK로 만들고, 고아 행은 경고와 함께 검사

    키는 행 다음에 만들고 마지막에 검사해요. 부모 행이 없는 행이 있으면 불러오기를 멈추지 않고 경고와 함께 검사하지 않은 상태로 남겨요.

  • ON DELETE or ON UPDATE that cascades in a cycle or along a second path

    NO ACTION

    SQL Server는 한 테이블에 두 번 닿을 수 있는 연쇄 동작을 거부하지만 PostgreSQL은 허용해요.

    보고서 줄: foreign_key_action_dropped

  • foreign keys to tables the dump doesn't create

    만들지 않음

    키는 없는 테이블을 가리킬 수 없어요.

    보고서 줄: foreign_key_skipped

  • partitioned tables

    모든 파티션의 행을 담은 하나의 테이블

    행은 같아요. 필요하면 SQL Server에서 테이블을 다시 파티션으로 나누세요.

    보고서 줄: partitions_dropped

  • views, functions, procedures, triggers, rules, policies, extensions and types

    보고서에 나열

    코드가 PostgreSQL의 언어로 작성되어 있어서 직접 다시 만들 수 있도록 나열해요.

    보고서 줄: 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

    잘못된 바이트를 대체 문자로

    nvarchar는 Unicode 텍스트를 담아요.

    보고서 줄: invalid_utf8_replaced

  • text decoded twice (ñ)

    그대로 복사

    덤프에 정확히 이 문자들이 있으므로 그대로 복사하고, 보고서에서 알려 줘요.

    보고서 줄: mojibake_suspected

PostgreSQL에서SQL Server에서보고서 줄
booleanbitbit는 true를 1, false를 0으로 담아요.
varchar(n), char(n), textnvarchar(n), text는 nvarchar(max), 키에 쓰이고 모든 값이 들어가면 nvarchar(450)nvarchar는 모든 문자를 담아요. SQL Server는 nvarchar(max)를 인덱싱할 수 없어서 키에 있는 텍스트는 키에 맞는 크기로 정해요.
text comparison정확히 비교(Latin1_General_100_BIN2), citext는 대소문자 무시(Latin1_General_100_CI_AS_SC)SQL Server의 일반적인 콜레이션은 대소문자를 무시하지만 PostgreSQL의 텍스트는 그렇지 않아요. 그래서 열마다 비교 방식을 지정하고, 고유 키는 같은 행들을 구분해요.
numeric(p,s) past 38 digits; numeric without a precisionnvarchar, 값이 38자리에 들어가면 값에 맞춘 decimal(p,s)SQL Server의 decimal은 38자리까지 담아요. 정밀도가 없는 numeric은 값이 들어가는 가장 좁은 decimal이 되고, 더 넓은 숫자는 모든 자릿수가 정확하도록 텍스트로 유지해요.decimal_as_text
moneydecimal(19,2)SQL Server의 money는 PostgreSQL보다 작고 소수 4자리예요. decimal(19,2)는 서버 로캘이 붙인 통화 기호 없이 모든 금액을 담아요.type_replaced
intervalPostgreSQL의 텍스트를 담은 nvarchar(100)SQL Server에는 interval 타입이 없어요. 텍스트가 모든 부분을 유지해요.type_replaced
arrays (integer[], text[]...)JSON 배열을 담은 nvarchar(max)SQL Server에는 배열이 없어요. JSON 배열은 모든 항목과 NULL을 유지하고 OPENJSON으로 읽을 수 있어요.type_replaced
ranges, geometric types, tsvector, xml, hstore, PostGIS, composite and extension typesPostgreSQL의 텍스트를 담은 nvarchar(max)SQL Server에는 같은 타입이 없어서 각 값은 PostgreSQL이 쓴 텍스트를 유지해요.type_replaced
json, jsonbnvarchar(max)SQL Server의 JSON 함수는 텍스트에서 JSON을 읽어요.
timestampdatetime2timestamp without time zone은 datetime2처럼 시계에 표시된 시각이에요.
timestamp with time zoneUTC 기준 datetimeoffsetdatetimeoffset은 시점을 유지해요. 각 값은 UTC로 쓰며, 덤프에 적힌 오프셋과 상관없이 같은 시점이에요.
time with 24:00:00 in itnvarchar(17)SQL Server의 time은 23:59:59.9999999에서 끝나서 24:00:00이 있는 열은 텍스트를 유지해요.time_as_interval
infinity, -infinity and BC datesNULLSQL Server는 1년부터 9999년까지만 저장하고 infinity는 없어요. 이 값은 NULL이 되고 보고서에 개수가 나와요.date_out_of_range
NaN and Infinity in numeric, real and double precisionNULLSQL Server의 숫자에는 NaN이나 Infinity가 없어서 이 값은 NULL이 되고 보고서에 개수가 나와요.invalid_value_null
NOT NULL columns with values that become NULLNOT NULL 제거값을 NULL로 바꿔야 했던 열은 NOT NULL을 유지할 수 없어요. 유지하면 불러오기가 멈춰요.not_null_relaxed
enum types레이블 CHECK가 붙은 nvarchar체크 제약이 있는 텍스트는 같은 값을 유지해요.
enum columns holding values outside their labels체크 제약 없는 nvarchar레이블에 없는 값은 체크 제약에 걸리므로 체크 제약을 만들지 않아요.enum_check_skipped
uuid, inet, cidr, macaddruniqueidentifier, 주소는 nvarcharuniqueidentifier는 SQL Server의 UUID예요. 주소는 텍스트로 유지해요.
byteavarbinary(max)바이트는 바이트 그대로 남아요.
bit(n), bit varying1비트는 bit, 63비트까지는 bigint, 그 이상은 자릿수 텍스트1비트는 예/아니요이고, 더 긴 비트 문자열은 비트가 만드는 숫자로 저장해요.
oid, xid, cid음수가 아닌지 확인하는 CHECK가 붙은 bigintbigint는 모든 값을 담아요.
serial, identityIDENTITY, 가장 큰 id 다음부터 이어짐복사된 id는 IDENTITY_INSERT로 불러오고, 카운터는 가장 큰 id와 시퀀스의 다음 값 중 더 큰 값 다음부터 이어져요.
a second serial or identity column in a table일반 정수SQL Server는 테이블마다 IDENTITY 열 하나만 번호를 매겨요. 다른 열은 카운터 없이 값을 유지해요.counter_dropped
sequences not owned by a column다음 값을 포함한 CREATE SEQUENCE ... AS bigintSQL Server에도 같은 옵션의 시퀀스가 있어요. 각 시퀀스는 덤프가 멈춘 곳부터 이어져요.
generated columns계산 열, 원본에서 저장되면 PERSISTEDSQL Server도 같은 두 가지 방식으로 계산해요.
generated columns with functions SQL Server lacks값을 담은 일반 열SQL Server용으로 쓸 수 없는 수식은 덤프의 값을 담은 일반 열로 남고 보고서에 한 줄 기록돼요.generated_not_translated
defaults with functions SQL Server lacks, and defaults from a sequence기본값 없음SQL Server용으로 쓸 수 없는 기본값은 제외하고 보고해요.default_not_translated
CHECK constraints변환해서 CREATE TABLE 안에 인라인으로인라인 체크 제약은 각 행을 불러올 때 검사해요.
CHECK constraints with functions SQL Server lacks만들지 않음SQL Server용으로 쓸 수 없는 체크 제약은 제외하고 보고해요.check_skipped
CHECK ... NOT VALID만들지 않음PostgreSQL은 기존 행을 검사한 적이 없어서 그 행이 제약을 어길 수 있어요.check_not_valid
gin, gist, brin and hash indexes, partial and expression indexes, and indexes on text that doesn't fit a key만들지 않음SQL Server는 식이 아닌 열을 인덱싱하고, nvarchar(max)는 인덱싱하지 않아요.index_skipped
foreign keys데이터 뒤에 WITH NOCHECK로 만들고, 고아 행은 경고와 함께 검사키는 행 다음에 만들고 마지막에 검사해요. 부모 행이 없는 행이 있으면 불러오기를 멈추지 않고 경고와 함께 검사하지 않은 상태로 남겨요.
ON DELETE or ON UPDATE that cascades in a cycle or along a second pathNO ACTIONSQL Server는 한 테이블에 두 번 닿을 수 있는 연쇄 동작을 거부하지만 PostgreSQL은 허용해요.foreign_key_action_dropped
foreign keys to tables the dump doesn't create만들지 않음키는 없는 테이블을 가리킬 수 없어요.foreign_key_skipped
partitioned tables모든 파티션의 행을 담은 하나의 테이블행은 같아요. 필요하면 SQL Server에서 테이블을 다시 파티션으로 나누세요.partitions_dropped
views, functions, procedures, triggers, rules, policies, extensions and types보고서에 나열코드가 PostgreSQL의 언어로 작성되어 있어서 직접 다시 만들 수 있도록 나열해요.not_converted_objects
dumps without CREATE TABLE (--data-only)값으로 판단한 타입데이터만 있는 덤프에는 행만 있어서 타입을 값으로 판단해요.no_schema
expressions in INSERT valuesNULL데이터베이스를 실행하지 않는 변환기는 이 식을 계산할 수 없어요.expression_value
types IntoSQL doesn't knownvarchar(max)텍스트는 어떤 값이든 담아요. 불러온 뒤 타입을 바꾸세요.unknown_type
text that isn't valid in its encoding잘못된 바이트를 대체 문자로nvarchar는 Unicode 텍스트를 담아요.invalid_utf8_replaced
text decoded twice (ñ)그대로 복사덤프에 정확히 이 문자들이 있으므로 그대로 복사하고, 보고서에서 알려 줘요.mojibake_suspected

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

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

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까지예요. 모든 버전에서 같은 스크립트를 불러올 수 있고, 문제가 생기면 첫 오류에서 멈춰요.