MySQL에서 SQL Server로 변환
mysqldump, mariadb-dump, mysqlpump, phpMyAdmin, Adminer에서 만든 .sql 또는 .sql.gz 덤프를 놓으면, 같은 테이블, 키, 인덱스, 데이터를 담은 SQL Server 스크립트를 다운로드할 수 있어요. SQL Server이(가) 그대로 담을 수 없는 값과 옮기지 않는 객체는 모두 보고서에 나와요.
18개 행 변환, 수정 10개, 거부 없음
shop_2024.sql의 테이블MySQL 8.0.46 덤프 · mysqldump(으)로 작성됨 · utf8mb4
customers8개 행4
7개 열 id bigint not null name nvarchar(200) not null email nvarchar(150) not null country nvarchar(2) not null is_active bit not null signed_up date created_at datetimeoffset(0) not null orders10개 행6
9개 열 id bigint not null customer_id bigint not null status nvarchar(9) not null total decimal(10,2) not null items int not null ordered_at datetime2(0) not null shipped_at datetime2(0) note nvarchar(510) updated_at datetimeoffset(0) not null
-- Written by IntoSQL from a MySQL 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] bigint IDENTITY(1001, 1) NOT NULL,
[name] nvarchar(200) NOT NULL,
[email] nvarchar(150) NOT NULL,
[country] nvarchar(2) DEFAULT N'US' NOT NULL,
[is_active] bit DEFAULT 1 NOT NULL,
[signed_up] date NULL,
[created_at] datetimeoffset(0) DEFAULT SYSDATETIMEOFFSET() NOT NULL,
CONSTRAINT [CK_customers_id] CHECK ([id] >= 0),
CONSTRAINT [PK_customers] PRIMARY KEY ([id])
);
GO
CREATE TABLE [dbo].[orders] (
[id] bigint IDENTITY(5001, 1) NOT NULL,
[customer_id] bigint NOT NULL,
[status] nvarchar(9) DEFAULT N'pending' NOT NULL,
[total] decimal(10,2) NOT NULL,
[items] int DEFAULT 1 NOT NULL,
[ordered_at] datetime2(0) NOT NULL,
[shipped_at] datetime2(0) NULL,
[note] nvarchar(510) NULL,
[updated_at] datetimeoffset(0) DEFAULT SYSDATETIMEOFFSET() NOT NULL,
CONSTRAINT [CK_orders_id] CHECK ([id] >= 0),
CONSTRAINT [CK_orders_customer_id] CHECK ([customer_id] >= 0),
CONSTRAINT [CK_orders_status] CHECK ([status] IN (N'pending', N'paid', N'shipped', N'cancelled', N'')),
CONSTRAINT [CK_orders_items] CHECK ([items] >= 0),
CONSTRAINT [PK_orders] PRIMARY KEY ([id])
);
GO
SET IDENTITY_INSERT [dbo].[customers] ON;
INSERT INTO [dbo].[customers] ([id], [name], [email], [country], [is_active], [signed_up], [created_at]) VALUES
(1,N'Ana Martínez',N'ana@example.com',N'MX',1,'2023-01-15','2023-01-15 10:24:00+00:00'),
(2,N'Zoë Müller',N'zoe@example.de',N'DE',1,'2023-02-03','2023-02-03 08:11:42+00:00'),
(3,N'José Peña',N'jose@example.es',N'ES',0,'2023-03-21','2023-03-21 19:05:17+00:00'),
(4,N'李雷',N'lilei@example.cn',N'CN',1,'2023-05-09','2023-05-09 02:40:00+00:00'),
(5,N'Noah O''Brien',N'noah@example.ie',N'IE',1,NULL,'2023-06-30 14:00:00+00:00'),
(6,N'Amélie Laurent',N'amelie@example.fr',N'FR',1,'2024-01-02','2024-01-02 09:30:00+00:00'),
(7,N'Ravi Patel',N'ravi@example.in',N'IN',0,'2024-02-29','2024-02-29 23:59:59+00:00'),
(8,N'Sofia Rossi 🌻',N'sofia@example.it',N'IT',1,'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], [updated_at]) VALUES
(1,1,N'shipped',129.90,3,'2024-03-01 10:00:00','2024-03-02 16:30:00',NULL,'2024-03-02 16:30:00+00:00'),
(2,2,N'paid',54.00,1,'2024-03-02 11:15:00',NULL,N'Gift wrap 🎁','2024-03-02 11:20:00+00:00'),
(3,1,N'cancelled',12.50,1,'2024-03-03 09:45:00',NULL,N'Customer changed their mind','2024-03-03 10:00:00+00:00'),
(4,4,N'shipped',980.00,12,'2024-03-05 02:10:00','2024-03-07 08:00:00',N'请小心轻放','2024-03-07 08:00:00+00:00'),
(5,5,N'pending',45.75,2,'2024-03-08 17:20:00',NULL,N'Leave at the door; ring twice','2024-03-08 17:20:00+00:00'),
(6,6,N'shipped',310.40,5,'2024-03-10 13:00:00','2024-03-11 09:00:00',N'Fragile: "glass"','2024-03-11 09:00:00+00:00'),
(7,8,N'paid',76.20,2,'2024-03-11 18:45:00',NULL,NULL,'2024-03-11 18:46:00+00:00'),
(8,2,N'',19.99,1,'2024-03-12 08:00:00',NULL,N'Status lost in an old import','2024-03-12 08:00:00+00:00'),
(9,3,N'shipped',64.00,2,'2024-03-14 15:30:00',NULL,N'Shipping date never recorded','2024-03-15 10:00:00+00:00'),
(10,7,N'paid',1499.00,1,'2024-03-15 21:05:00',NULL,N'C:\Users\ravi\invoice.pdf','2024-03-15 21:05:00+00:00');
SET IDENTITY_INSERT [dbo].[orders] OFF;
GO
-- Indexes, foreign keys, counters and triggers, after the rows.
CREATE UNIQUE INDEX [uq_email] ON [dbo].[customers] ([email]);
CREATE INDEX [idx_customer] ON [dbo].[orders] ([customer_id]);
CREATE INDEX [idx_status_date] ON [dbo].[orders] ([status], [ordered_at]);
ALTER TABLE [dbo].[orders] WITH NOCHECK ADD CONSTRAINT [fk_orders_customer] FOREIGN KEY ([customer_id]) REFERENCES [dbo].[customers] ([id]);
BEGIN TRY ALTER TABLE [dbo].[orders] WITH CHECK CHECK CONSTRAINT [fk_orders_customer]; END TRY BEGIN CATCH PRINT N'Foreign key ' + N'[fk_orders_customer]' + 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
CREATE TRIGGER [dbo].[TR_orders_updated_at_on_update] ON [dbo].[orders] AFTER UPDATE AS
BEGIN
SET NOCOUNT ON;
IF NOT UPDATE([updated_at])
UPDATE x SET [updated_at] = SYSDATETIMEOFFSET() FROM [dbo].[orders] AS x JOIN inserted AS i ON x.[id] = i.[id];
END;
GO
GO
수정 사항
- customers의 "id" 열은 부호가 없어서, 음수가 아닌지 확인하는 체크 제약과 함께 bigint(으)로 만들었어요.
- customers의 "name" 열에 이모지처럼 SQL Server이(가) 두 개로 세는 문자가 있어 nvarchar(200)(으)로 만들었어요.
- customers의 "signed_up" 열은 이제 NULL을 허용해요. 일부 값을 저장할 수 없어 NULL이 됐어요.
- customers의 "signed_up" 열 기본값 0000‑00‑00은(는) SQL Server이 받는 날짜가 아니라서 기본값을 없앴어요.
- orders의 "customer_id" 열은 부호가 없어서, 음수가 아닌지 확인하는 체크 제약과 함께 bigint(으)로 만들었어요.
- orders의 "id" 열은 부호가 없어서, 음수가 아닌지 확인하는 체크 제약과 함께 bigint(으)로 만들었어요.
- orders의 "items" 열은 부호가 없어서, 음수가 아닌지 확인하는 체크 제약과 함께 int(으)로 만들었어요.
- orders의 "note" 열에 이모지처럼 SQL Server이(가) 두 개로 세는 문자가 있어 nvarchar(510)(으)로 만들었어요.
- orders의 "status" 열에서 1개 행에 MySQL이 잘못된 입력에 저장하는 빈 값이 있어요. 값 체크 제약이 이 값을 허용해요.
- orders의 "updated_at" 열은 업데이트할 때마다 현재 시간으로 바뀌어요. SQL Server에서는 트리거가 이를 처리해요.
확인 필요
- customers의 "signed_up" 열에 있는 1개 값은 0000‑00‑00 같은 0 날짜나 불가능한 날짜예요. SQL Server이 저장할 수 없어 NULL로 두었어요. 이 날짜에 의미가 있다면 덤프하기 전에 원본에서 실제 날짜로 바꾸세요.
- orders의 "shipped_at" 열에 있는 1개 값은 0000‑00‑00 00:00:00 같은 0 날짜나 불가능한 날짜예요. SQL Server이 저장할 수 없어 NULL로 두었어요. 이 날짜에 의미가 있다면 덤프하기 전에 원본에서 실제 날짜로 바꾸세요.
파일은 이 컴퓨터에서 변환되고 업로드되지 않아요.
다른 샘플:
MySQL에서 SQL Server로 바뀌는 점
각 행은 변환기가 적용하는 규칙이며, 규칙이 데이터를 바꿀 때 보고서에 쓰는 줄이 함께 나와요.
TINYINT(1), BOOL
모든 값이 0 또는 1이면 bit, 아니면 smallint
MySQL의 BOOL은 -128부터 127까지 어떤 숫자든 담을 수 있는 TINYINT(1)이에요. 0과 1만 담은 열은 bit가 되고, 2나 -1을 담은 열은 값의 의미가 바뀌지 않도록 숫자로 남아요.
보고서 줄: bool_kept_numeric
UNSIGNED integers
TINYINT UNSIGNED는 tinyint. 나머지는 음수가 아닌지 확인하는 CHECK가 붙은 한 단계 넓은 정수. BIGINT UNSIGNED는 모든 값이 들어가면 bigint, 아니면 decimal(38,0)
SQL Server에는 0부터 255까지인 tinyint를 빼면 부호 없는 정수가 없어요. 더 넓은 타입이 부호 없는 범위 전체를 담고, 체크 제약이 MySQL처럼 음수를 막아요.
보고서 줄: unsigned_widened
ZEROFILL and display widths
제거
0 채움은 숫자를 표시하는 방식일 뿐 숫자의 일부가 아니에요. 숫자는 유지되며, 채움이 필요하면 읽을 때 형식을 지정하세요.
보고서 줄: zerofill_dropped
FLOAT(M,D)
real 또는 float, 소수 자릿수 없이
SQL Server 부동소수점에는 고정 소수 자릿수가 없어요. 저장된 값은 그대로 복사돼요.
보고서 줄: float_scale_dropped
DECIMAL(p,s)
38자리까지는 decimal(p,s), 그 이상은 nvarchar
SQL Server의 decimal은 38자리까지 담아요. 더 넓은 소수는 모든 자릿수가 정확하도록 텍스트로 유지해요.
보고서 줄: decimal_as_text
BIT(1), BIT(n)
bit. 63비트까지는 bigint, BIT(64)는 decimal(20,0)
비트 하나는 예 또는 아니요이고, 더 넓은 비트 필드는 비트가 만드는 숫자로 저장해요.
zero, partial or impossible dates (0000-00-00, 2024-02-30)
NULL
SQL Server는 실제 달력 날짜만 저장해요. MySQL은 SQL 모드가 허용하면 0 날짜와 불가능한 날짜를 보관해요. 이 값은 NULL이 되고 보고서에 개수가 나와요.
보고서 줄: invalid_date_null
NOT NULL columns with values that become NULL
NOT NULL 제거
값을 NULL로 바꿔야 했던 열은 NOT NULL을 유지할 수 없어요. 유지하면 불러오기가 멈춰요.
보고서 줄: not_null_relaxed
DEFAULT '0000-00-00'
기본값 없음
SQL Server가 저장할 수 없는 기본값은 지어낸 날짜로 바꾸지 않고 제외해요.
보고서 줄: zero_date_default
TIME
모든 값이 하루 안이면 time, 아니면 nvarchar
MySQL의 TIME은 -838:59:59부터 838:59:59까지의 기간이고, SQL Server의 time은 하루 중 시각이에요. 더 길거나 음수인 값이 있는 열은 텍스트로 유지해요.
보고서 줄: time_as_interval
YEAR
범위 CHECK가 붙은 smallint
SQL Server에는 연도 타입이 없어요. 체크 제약이 MySQL이 허용하는 값과 같은 값만 받아요.
CHAR(n), VARCHAR(n)
nvarchar(n)
nvarchar는 지원하는 모든 버전에서 모든 문자를 담아요. MySQL은 CHAR 값을 끝의 공백 없이 돌려주고, nvarchar는 그대로 유지해요.
text with characters past U+FFFF (emoji) in VARCHAR(n)
nvarchar(2n), 4000을 넘으면 nvarchar(max)
nvarchar는 UTF-16 단위로 세고 이모지는 두 단위를 차지하므로, 열에 모든 값이 들어갈 공간을 줘요.
보고서 줄: text_length_widened
DATETIME
datetime2
DATETIME은 datetime2처럼 시간대 없이 시계에 표시된 시각이에요.
TIMESTAMP
덤프에 명시된 시간대의 datetimeoffset, 명시가 없으면 UTC
TIMESTAMP는 한 시점이에요. 덤프는 기록한 시간대를 명시해요(mysqldump는 UTC로 기록해요). 명시가 없으면 값을 UTC로 읽고 보고서에 그렇게 적어요.
보고서 줄: timestamp_zone_assumed
ENUM
값 CHECK가 붙은 nvarchar
체크 제약이 있는 텍스트는 같은 값을 유지해요.
ENUM holding '' (MySQL's error value)
체크 제약이 허용하는 빈 값
느슨한 SQL 모드에서 ENUM에 잘못된 값이 들어가면 MySQL은 빈 문자열을 저장해요. 이 행은 유지되고 체크 제약이 이를 허용해요.
보고서 줄: enum_invalid_value
ENUM holding values outside its list
CHECK 없음
목록에 없는 값은 체크 제약에 걸리므로 체크 제약을 만들지 않아요.
보고서 줄: enum_check_skipped
SET
MySQL이 쓰는 그대로의 nvarchar('a,b')
SQL Server에는 배열이 없어요. 텍스트는 MySQL이 돌려주는 값과 같아요.
JSON
nvarchar(max)
SQL Server의 JSON 함수는 텍스트에서 JSON을 읽어요. ISJSON 체크 제약은 SQL Server 2022 이전에 1이나 "x" 같은 스칼라 값을 거부하는데, MySQL은 이 값을 유지해요.
NUL bytes in text
유지
nvarchar는 NUL 문자를 담을 수 있어서 값을 그대로 복사해요.
text that isn't valid in its character set
잘못된 바이트를 대체 문자로
nvarchar로 쓰려면 텍스트를 문자로 읽어야 해요.
보고서 줄: invalid_utf8_replaced
text decoded twice (ñ)
그대로 복사
덤프에 정확히 이 문자들이 있으므로 그대로 복사하고, 보고서에서 알려 줘요.
보고서 줄: mojibake_suspected
AUTO_INCREMENT
IDENTITY, 카운터는 복사된 id 다음부터
복사된 id는 IDENTITY_INSERT로 불러오고, 카운터는 가장 큰 id와 덤프의 AUTO_INCREMENT 중 더 큰 값 다음부터 이어져요.
MyISAM AUTO_INCREMENT on the second column of a key
테이블당 카운터 하나
MyISAM은 키의 첫 열 그룹마다 따로 세지만, SQL Server는 테이블마다 카운터가 하나예요.
보고서 줄: myisam_group_autoincrement
ON UPDATE CURRENT_TIMESTAMP
AFTER UPDATE 트리거
업데이트에서 열을 지정하지 않으면 트리거가 열을 현재 시간으로 설정해요. 기본 키로 조인하므로 테이블에 기본 키가 필요해요.
보고서 줄: on_update_trigger
ON UPDATE CURRENT_TIMESTAMP on a table without a primary key
옮기지 않음
트리거는 업데이트된 행을 기본 키로 찾아요. 기본 키가 없으면 찾을 수 없어요.
보고서 줄: on_update_without_key
generated columns
계산 열, 원본에서 저장되면 PERSISTED
SQL Server도 같은 두 가지 방식으로 계산해요.
generated columns with functions SQL Server lacks
일반 열
SQL Server용으로 쓸 수 없는 수식은 일반 열로 남고 보고서에 한 줄 기록돼요.
보고서 줄: generated_not_translated
INVISIBLE columns
일반 열
SQL Server에는 보이지 않는 열이 없어요.
보고서 줄: invisible_column
CHECK constraints
변환해서 CREATE TABLE 안에 인라인으로
인라인 체크 제약은 각 행을 불러올 때 검사해요.
CHECK constraints with functions SQL Server lacks
만들지 않음
SQL Server용으로 쓸 수 없는 체크 제약은 제외하고 보고해요.
보고서 줄: check_skipped
CHECK ... NOT ENFORCED
만들지 않음
MySQL은 이 체크 제약을 적용하지 않고 보관만 하므로, 행이 제약을 어길 수 있어요.
보고서 줄: check_not_enforced
defaults with functions SQL Server lacks
기본값 없음
SQL Server용으로 쓸 수 없는 기본값은 제외하고 보고해요.
보고서 줄: default_not_translated
keys and indexes on a prefix, c(20)
열 전체에 대한 인덱스
SQL Server는 열 전체를 인덱싱해요. 접두부에서 고유한 키는 열 전체에서도 고유하므로 모든 행이 불러와져요.
보고서 줄: prefix_whole_column
FULLTEXT indexes
만들지 않음
SQL Server의 전문 검색에는 카탈로그와 전용 쿼리가 필요해요.
보고서 줄: fulltext_not_created
SPATIAL indexes
만들지 않음
지오메트리 열의 공간 인덱스에는 덤프에 명시되지 않은 경계 상자가 필요해요.
보고서 줄: spatial_index_not_created
functional indexes, and indexes on columns of unlimited length
만들지 않음
SQL Server는 식도, nvarchar(max)와 varbinary(max) 열도 인덱싱하지 않아요.
보고서 줄: index_skipped
foreign keys
데이터 뒤에 WITH NOCHECK로 만들고, 고아 행은 경고와 함께 검사
덤프는 FOREIGN_KEY_CHECKS=0으로 불러오고 MyISAM은 전혀 확인하지 않으므로, 부모 없는 행이 흔해요. 키를 먼저 만들고 마지막에 검사해요. 고아 행이 있으면 불러오기를 멈추지 않고 경고와 함께 검사하지 않은 채로 남겨요.
ON DELETE or ON UPDATE that cascades in a cycle or along a second path
NO ACTION
SQL Server는 한 테이블에 두 번 닿을 수 있는 연쇄 동작을 거부하지만, MySQL은 허용해요.
보고서 줄: foreign_key_action_dropped
foreign keys to columns without a unique key
만들지 않음
SQL Server는 참조되는 열에 기본 키나 NULL 없는 고유 인덱스가 필요하지만 InnoDB는 그렇지 않아요.
보고서 줄: foreign_key_skipped
table and column names
쓴 그대로. 대소문자만 다르면 이름 변경
SQL Server 이름은 일반적인 콜레이션에서 대소문자를 구분하지 않아요.
보고서 줄: identifier_renamed
names over 116 characters
줄임
SQL Server 이름은 128자까지이며, 그중 일부는 이름을 구분하는 번호에 쓰여요.
보고서 줄: name_shortened
GEOMETRY, POINT, POLYGON...
geometry, 값마다 SRID 포함
SQL Server 고유의 geometry 타입은 모든 도형과 공간 참조 체계를 유지해요.
INET4, INET6, UUID (MariaDB)
nvarchar(39), uniqueidentifier
uniqueidentifier는 SQL Server의 UUID예요. 주소는 텍스트로 유지해요.
BINARY, VARBINARY, BLOB
binary, varbinary, varbinary(max)
바이트는 바이트 그대로 남아요.
PARTITION BY
하나의 테이블
행은 같아요. 필요하면 SQL Server에서 테이블을 다시 파티션으로 나누세요.
보고서 줄: partitions_dropped
WITH SYSTEM VERSIONING (MariaDB)
현재 행만 담은 테이블
덤프에는 현재 행만 들어 있어요.
보고서 줄: system_versioning_dropped
MyISAM, MEMORY and other engines
일반 테이블
SQL Server의 테이블 엔진은 하나예요.
보고서 줄: engine_dropped
views, triggers, procedures, functions and events
보고서에 나열
이 객체들의 코드는 MySQL 언어로 작성되어 있어서, 직접 다시 만들 수 있도록 나열해요.
보고서 줄: not_converted_objects
dumps without CREATE TABLE
값으로 판단한 타입
--no-create-info로 만든 덤프에는 행만 있어서 타입을 값으로 판단해요.
보고서 줄: no_schema
geometries in a dump without CREATE TABLE
geometry
MySQL의 지오메트리 형식을 값에서 알아봐요.
_ci collations
데이터베이스의 콜레이션, 보통 대소문자 구분 없음
SQL Server는 일반적인 콜레이션에서 MySQL의 _ci처럼 대소문자 구분 없이 텍스트를 비교해요.
SET NAMES utf8 from utf8mb4 tables
변환하고 경고 표시
MySQL 5.x의 mysqldump는 기본으로 3바이트 utf8을 쓰고, 변환기가 파일을 보기 전에 모든 이모지를 물음표로 바꿔요.
보고서 줄: dump_lost_four_byte_chars
dumps without SET NAMES whose text isn't UTF-8
Latin-1 (Windows-1252)로 읽음
MySQL의 latin1은 Windows-1252이며, 이런 덤프에서 흔히 쓰는 인코딩이에요.
보고서 줄: charset_guessed
sjis, cp932, gbk, big5 dumps
UTF-8로 읽고 경고 표시
이 인코딩은 아직 디코딩하지 않아요.
보고서 줄: unsupported_charset
UNHEX('..'), CONVERT(b'..', UNSIGNED), CONVERT(".." USING x), ST_GeomFromText('..') in rows
계산함
일부 덤프 도구는 값을 이런 함수 호출로 써요. 호출이 만드는 값으로 읽고, 지리 WKT는 경도가 먼저 오도록 바꿔요.
other expressions in rows
NULL
데이터베이스를 실행하지 않는 변환기는 이 식을 계산할 수 없어요.
보고서 줄: expression_value
DEFAULT in VALUES
열의 기본값
리터럴 기본값을 행에 복사해요.
보고서 줄: default_keyword_filled
DEFAULT in VALUES without a literal default
NULL
복사할 값이 없어요.
보고서 줄: default_keyword_null
REPLACE and INSERT IGNORE
일반 행
덤프에는 키마다 행이 하나라서 행은 같아요.
보고서 줄: replace_as_insert
types IntoSQL doesn't know
nvarchar(max)
텍스트는 어떤 값이든 담아요. 불러온 뒤 타입을 바꾸세요.
보고서 줄: unknown_type
values that don't fit their column
NULL
손상되었거나 직접 작성한 덤프에는 열이 담을 수 없는 값이 있을 수 있어요. 나머지를 불러올 수 있도록 이 값은 NULL이 돼요.
보고서 줄: invalid_value_null
unreadable geometries
NULL
지오메트리가 아닌 바이트는 지오메트리로 저장할 수 없어요.
보고서 줄: bad_geometry
CREATE SEQUENCE (MariaDB)
다음 값을 포함한 CREATE SEQUENCE ... AS bigint
SQL Server에도 같은 옵션의 시퀀스가 있어요. 각 시퀀스는 덤프가 멈춘 곳부터 이어져요.
VECTOR(n) (MariaDB 11.7+)
부동소수점 값을 JSON 배열로 담은 nvarchar(max)
vector 타입은 SQL Server 2025에만 있어요. JSON 배열은 모든 버전에서 모든 부동소수점 값을 유지해요.
보고서 줄: type_replaced
| MySQL에서 | SQL Server에서 | 보고서 줄 |
|---|---|---|
| TINYINT(1), BOOL | 모든 값이 0 또는 1이면 bit, 아니면 smallintMySQL의 BOOL은 -128부터 127까지 어떤 숫자든 담을 수 있는 TINYINT(1)이에요. 0과 1만 담은 열은 bit가 되고, 2나 -1을 담은 열은 값의 의미가 바뀌지 않도록 숫자로 남아요. | bool_kept_numeric |
| UNSIGNED integers | TINYINT UNSIGNED는 tinyint. 나머지는 음수가 아닌지 확인하는 CHECK가 붙은 한 단계 넓은 정수. BIGINT UNSIGNED는 모든 값이 들어가면 bigint, 아니면 decimal(38,0)SQL Server에는 0부터 255까지인 tinyint를 빼면 부호 없는 정수가 없어요. 더 넓은 타입이 부호 없는 범위 전체를 담고, 체크 제약이 MySQL처럼 음수를 막아요. | unsigned_widened |
| ZEROFILL and display widths | 제거0 채움은 숫자를 표시하는 방식일 뿐 숫자의 일부가 아니에요. 숫자는 유지되며, 채움이 필요하면 읽을 때 형식을 지정하세요. | zerofill_dropped |
| FLOAT(M,D) | real 또는 float, 소수 자릿수 없이SQL Server 부동소수점에는 고정 소수 자릿수가 없어요. 저장된 값은 그대로 복사돼요. | float_scale_dropped |
| DECIMAL(p,s) | 38자리까지는 decimal(p,s), 그 이상은 nvarcharSQL Server의 decimal은 38자리까지 담아요. 더 넓은 소수는 모든 자릿수가 정확하도록 텍스트로 유지해요. | decimal_as_text |
| BIT(1), BIT(n) | bit. 63비트까지는 bigint, BIT(64)는 decimal(20,0)비트 하나는 예 또는 아니요이고, 더 넓은 비트 필드는 비트가 만드는 숫자로 저장해요. | |
| zero, partial or impossible dates (0000-00-00, 2024-02-30) | NULLSQL Server는 실제 달력 날짜만 저장해요. MySQL은 SQL 모드가 허용하면 0 날짜와 불가능한 날짜를 보관해요. 이 값은 NULL이 되고 보고서에 개수가 나와요. | invalid_date_null |
| NOT NULL columns with values that become NULL | NOT NULL 제거값을 NULL로 바꿔야 했던 열은 NOT NULL을 유지할 수 없어요. 유지하면 불러오기가 멈춰요. | not_null_relaxed |
| DEFAULT '0000-00-00' | 기본값 없음SQL Server가 저장할 수 없는 기본값은 지어낸 날짜로 바꾸지 않고 제외해요. | zero_date_default |
| TIME | 모든 값이 하루 안이면 time, 아니면 nvarcharMySQL의 TIME은 -838:59:59부터 838:59:59까지의 기간이고, SQL Server의 time은 하루 중 시각이에요. 더 길거나 음수인 값이 있는 열은 텍스트로 유지해요. | time_as_interval |
| YEAR | 범위 CHECK가 붙은 smallintSQL Server에는 연도 타입이 없어요. 체크 제약이 MySQL이 허용하는 값과 같은 값만 받아요. | |
| CHAR(n), VARCHAR(n) | nvarchar(n)nvarchar는 지원하는 모든 버전에서 모든 문자를 담아요. MySQL은 CHAR 값을 끝의 공백 없이 돌려주고, nvarchar는 그대로 유지해요. | |
| text with characters past U+FFFF (emoji) in VARCHAR(n) | nvarchar(2n), 4000을 넘으면 nvarchar(max)nvarchar는 UTF-16 단위로 세고 이모지는 두 단위를 차지하므로, 열에 모든 값이 들어갈 공간을 줘요. | text_length_widened |
| DATETIME | datetime2DATETIME은 datetime2처럼 시간대 없이 시계에 표시된 시각이에요. | |
| TIMESTAMP | 덤프에 명시된 시간대의 datetimeoffset, 명시가 없으면 UTCTIMESTAMP는 한 시점이에요. 덤프는 기록한 시간대를 명시해요(mysqldump는 UTC로 기록해요). 명시가 없으면 값을 UTC로 읽고 보고서에 그렇게 적어요. | timestamp_zone_assumed |
| ENUM | 값 CHECK가 붙은 nvarchar체크 제약이 있는 텍스트는 같은 값을 유지해요. | |
| ENUM holding '' (MySQL's error value) | 체크 제약이 허용하는 빈 값느슨한 SQL 모드에서 ENUM에 잘못된 값이 들어가면 MySQL은 빈 문자열을 저장해요. 이 행은 유지되고 체크 제약이 이를 허용해요. | enum_invalid_value |
| ENUM holding values outside its list | CHECK 없음목록에 없는 값은 체크 제약에 걸리므로 체크 제약을 만들지 않아요. | enum_check_skipped |
| SET | MySQL이 쓰는 그대로의 nvarchar('a,b')SQL Server에는 배열이 없어요. 텍스트는 MySQL이 돌려주는 값과 같아요. | |
| JSON | nvarchar(max)SQL Server의 JSON 함수는 텍스트에서 JSON을 읽어요. ISJSON 체크 제약은 SQL Server 2022 이전에 1이나 "x" 같은 스칼라 값을 거부하는데, MySQL은 이 값을 유지해요. | |
| NUL bytes in text | 유지nvarchar는 NUL 문자를 담을 수 있어서 값을 그대로 복사해요. | |
| text that isn't valid in its character set | 잘못된 바이트를 대체 문자로nvarchar로 쓰려면 텍스트를 문자로 읽어야 해요. | invalid_utf8_replaced |
| text decoded twice (ñ) | 그대로 복사덤프에 정확히 이 문자들이 있으므로 그대로 복사하고, 보고서에서 알려 줘요. | mojibake_suspected |
| AUTO_INCREMENT | IDENTITY, 카운터는 복사된 id 다음부터복사된 id는 IDENTITY_INSERT로 불러오고, 카운터는 가장 큰 id와 덤프의 AUTO_INCREMENT 중 더 큰 값 다음부터 이어져요. | |
| MyISAM AUTO_INCREMENT on the second column of a key | 테이블당 카운터 하나MyISAM은 키의 첫 열 그룹마다 따로 세지만, SQL Server는 테이블마다 카운터가 하나예요. | myisam_group_autoincrement |
| ON UPDATE CURRENT_TIMESTAMP | AFTER UPDATE 트리거업데이트에서 열을 지정하지 않으면 트리거가 열을 현재 시간으로 설정해요. 기본 키로 조인하므로 테이블에 기본 키가 필요해요. | on_update_trigger |
| ON UPDATE CURRENT_TIMESTAMP on a table without a primary key | 옮기지 않음트리거는 업데이트된 행을 기본 키로 찾아요. 기본 키가 없으면 찾을 수 없어요. | on_update_without_key |
| generated columns | 계산 열, 원본에서 저장되면 PERSISTEDSQL Server도 같은 두 가지 방식으로 계산해요. | |
| generated columns with functions SQL Server lacks | 일반 열SQL Server용으로 쓸 수 없는 수식은 일반 열로 남고 보고서에 한 줄 기록돼요. | generated_not_translated |
| INVISIBLE columns | 일반 열SQL Server에는 보이지 않는 열이 없어요. | invisible_column |
| CHECK constraints | 변환해서 CREATE TABLE 안에 인라인으로인라인 체크 제약은 각 행을 불러올 때 검사해요. | |
| CHECK constraints with functions SQL Server lacks | 만들지 않음SQL Server용으로 쓸 수 없는 체크 제약은 제외하고 보고해요. | check_skipped |
| CHECK ... NOT ENFORCED | 만들지 않음MySQL은 이 체크 제약을 적용하지 않고 보관만 하므로, 행이 제약을 어길 수 있어요. | check_not_enforced |
| defaults with functions SQL Server lacks | 기본값 없음SQL Server용으로 쓸 수 없는 기본값은 제외하고 보고해요. | default_not_translated |
| keys and indexes on a prefix, c(20) | 열 전체에 대한 인덱스SQL Server는 열 전체를 인덱싱해요. 접두부에서 고유한 키는 열 전체에서도 고유하므로 모든 행이 불러와져요. | prefix_whole_column |
| FULLTEXT indexes | 만들지 않음SQL Server의 전문 검색에는 카탈로그와 전용 쿼리가 필요해요. | fulltext_not_created |
| SPATIAL indexes | 만들지 않음지오메트리 열의 공간 인덱스에는 덤프에 명시되지 않은 경계 상자가 필요해요. | spatial_index_not_created |
| functional indexes, and indexes on columns of unlimited length | 만들지 않음SQL Server는 식도, nvarchar(max)와 varbinary(max) 열도 인덱싱하지 않아요. | index_skipped |
| foreign keys | 데이터 뒤에 WITH NOCHECK로 만들고, 고아 행은 경고와 함께 검사덤프는 FOREIGN_KEY_CHECKS=0으로 불러오고 MyISAM은 전혀 확인하지 않으므로, 부모 없는 행이 흔해요. 키를 먼저 만들고 마지막에 검사해요. 고아 행이 있으면 불러오기를 멈추지 않고 경고와 함께 검사하지 않은 채로 남겨요. | |
| ON DELETE or ON UPDATE that cascades in a cycle or along a second path | NO ACTIONSQL Server는 한 테이블에 두 번 닿을 수 있는 연쇄 동작을 거부하지만, MySQL은 허용해요. | foreign_key_action_dropped |
| foreign keys to columns without a unique key | 만들지 않음SQL Server는 참조되는 열에 기본 키나 NULL 없는 고유 인덱스가 필요하지만 InnoDB는 그렇지 않아요. | foreign_key_skipped |
| table and column names | 쓴 그대로. 대소문자만 다르면 이름 변경SQL Server 이름은 일반적인 콜레이션에서 대소문자를 구분하지 않아요. | identifier_renamed |
| names over 116 characters | 줄임SQL Server 이름은 128자까지이며, 그중 일부는 이름을 구분하는 번호에 쓰여요. | name_shortened |
| GEOMETRY, POINT, POLYGON... | geometry, 값마다 SRID 포함SQL Server 고유의 geometry 타입은 모든 도형과 공간 참조 체계를 유지해요. | |
| INET4, INET6, UUID (MariaDB) | nvarchar(39), uniqueidentifieruniqueidentifier는 SQL Server의 UUID예요. 주소는 텍스트로 유지해요. | |
| BINARY, VARBINARY, BLOB | binary, varbinary, varbinary(max)바이트는 바이트 그대로 남아요. | |
| PARTITION BY | 하나의 테이블행은 같아요. 필요하면 SQL Server에서 테이블을 다시 파티션으로 나누세요. | partitions_dropped |
| WITH SYSTEM VERSIONING (MariaDB) | 현재 행만 담은 테이블덤프에는 현재 행만 들어 있어요. | system_versioning_dropped |
| MyISAM, MEMORY and other engines | 일반 테이블SQL Server의 테이블 엔진은 하나예요. | engine_dropped |
| views, triggers, procedures, functions and events | 보고서에 나열이 객체들의 코드는 MySQL 언어로 작성되어 있어서, 직접 다시 만들 수 있도록 나열해요. | not_converted_objects |
| dumps without CREATE TABLE | 값으로 판단한 타입--no-create-info로 만든 덤프에는 행만 있어서 타입을 값으로 판단해요. | no_schema |
| geometries in a dump without CREATE TABLE | geometryMySQL의 지오메트리 형식을 값에서 알아봐요. | |
| _ci collations | 데이터베이스의 콜레이션, 보통 대소문자 구분 없음SQL Server는 일반적인 콜레이션에서 MySQL의 _ci처럼 대소문자 구분 없이 텍스트를 비교해요. | |
| SET NAMES utf8 from utf8mb4 tables | 변환하고 경고 표시MySQL 5.x의 mysqldump는 기본으로 3바이트 utf8을 쓰고, 변환기가 파일을 보기 전에 모든 이모지를 물음표로 바꿔요. | dump_lost_four_byte_chars |
| dumps without SET NAMES whose text isn't UTF-8 | Latin-1 (Windows-1252)로 읽음MySQL의 latin1은 Windows-1252이며, 이런 덤프에서 흔히 쓰는 인코딩이에요. | charset_guessed |
| sjis, cp932, gbk, big5 dumps | UTF-8로 읽고 경고 표시이 인코딩은 아직 디코딩하지 않아요. | unsupported_charset |
| UNHEX('..'), CONVERT(b'..', UNSIGNED), CONVERT(".." USING x), ST_GeomFromText('..') in rows | 계산함일부 덤프 도구는 값을 이런 함수 호출로 써요. 호출이 만드는 값으로 읽고, 지리 WKT는 경도가 먼저 오도록 바꿔요. | |
| other expressions in rows | NULL데이터베이스를 실행하지 않는 변환기는 이 식을 계산할 수 없어요. | expression_value |
| DEFAULT in VALUES | 열의 기본값리터럴 기본값을 행에 복사해요. | default_keyword_filled |
| DEFAULT in VALUES without a literal default | NULL복사할 값이 없어요. | default_keyword_null |
| REPLACE and INSERT IGNORE | 일반 행덤프에는 키마다 행이 하나라서 행은 같아요. | replace_as_insert |
| types IntoSQL doesn't know | nvarchar(max)텍스트는 어떤 값이든 담아요. 불러온 뒤 타입을 바꾸세요. | unknown_type |
| values that don't fit their column | NULL손상되었거나 직접 작성한 덤프에는 열이 담을 수 없는 값이 있을 수 있어요. 나머지를 불러올 수 있도록 이 값은 NULL이 돼요. | invalid_value_null |
| unreadable geometries | NULL지오메트리가 아닌 바이트는 지오메트리로 저장할 수 없어요. | bad_geometry |
| CREATE SEQUENCE (MariaDB) | 다음 값을 포함한 CREATE SEQUENCE ... AS bigintSQL Server에도 같은 옵션의 시퀀스가 있어요. 각 시퀀스는 덤프가 멈춘 곳부터 이어져요. | |
| VECTOR(n) (MariaDB 11.7+) | 부동소수점 값을 JSON 배열로 담은 nvarchar(max)vector 타입은 SQL Server 2025에만 있어요. JSON 배열은 모든 버전에서 모든 부동소수점 값을 유지해요. | type_replaced |
스크립트를 SQL Server에 불러오기
스크립트는 테이블을 만들고 행을 복사한 다음 키, 인덱스, 외래 키를 추가해요. 그래서 빨리 불러오고 첫 오류에서 멈춰요.
sqlcmd -b -f 65001 -S localhost -d mydb -i mysql.sql_server.sql외래 키는 WITH NOCHECK로 추가한 다음 검사해요. 어떤 행이 존재하지 않는 행을 가리키면, 중간에 실패하지 않고 어떤 제약인지 알려 주고 그 제약은 검사하지 않은 채로 남겨요.
큰 덤프는 서버와 같은 컴퓨터에서 sqlcmd를 실행하세요. 최대 1000행의 배치마다 따로 커밋하므로 트랜잭션 로그가 작게 유지돼요.
좋은 결과를 위한 MySQL 덤프 방법
변환기는 덤프에 담긴 내용을 읽어요. 다음 옵션을 쓰면 더 많은 데이터가 덤프에 남아요:
- --default-character-set=utf8mb4는 이모지와 기타 4바이트 문자를 유지해요. utf8 덤프는 변환기가 보기 전에 이 문자를 잃어요.
- --hex-blob은 바이너리 열을 16진수로 써서, 시스템 간에 복사해도 손상되지 않아요.
- --routines --triggers --events는 이 객체들을 덤프에 추가해서 보고서에 나열할 수 있게 해요.
변환되지 않는 것
뷰, 트리거, 저장 프로시저, 함수, 이벤트는 데이터베이스마다 자체 언어로 작성돼요. 보고서에 이름으로 나열되고 몰래 빠지는 일은 없으므로, SQL Server에 맞게 다시 작성할 수 있어요.
MySQL에서 SQL Server로 변환에 관한 질문
여기에 답이 없나요? 문의 페이지로 연락하시면 담당자가 답장해요. 문의 페이지
덤프가 업로드되나요?
아니요. 변환기는 브라우저에서 실행되고 디스크의 덤프를 조각조각 읽으므로, 덤프가 컴퓨터 밖으로 나가지 않아요. 데스크톱 앱과 명령줄도 컴퓨터에서 변환해요.
덤프는 얼마나 커도 되나요?
변환기는 덤프 전체를 메모리에 올리지 않아요. 파일을 범위별로 두 번 읽고, 읽는 대로 스크립트를 써요. 수 GB 덤프도 브라우저, 데스크톱 앱, 명령줄에서 변환돼요.
MariaDB 덤프도 읽나요?
네. mariadb-dump와 MariaDB 10.3부터 12까지의 덤프도 같은 방식으로 변환되며, MariaDB의 INET6, INET4, UUID 열도 포함돼요.
0000-00-00 날짜는 어떻게 되나요?
SQL Server에는 0 날짜가 없어서 NULL이 되고, 열은 NULL을 허용하게 돼요. 열마다 몇 개였는지 보고서에 나와요.
AUTO_INCREMENT 값은 유지되나요?
네. 각 AUTO_INCREMENT 열은 IDENTITY 열이 되고, 모든 행은 id를 유지해요. 다음 id는 가장 큰 id 다음부터 이어지고, 테이블의 AUTO_INCREMENT가 더 크면 그 다음부터 이어져요.
TINYINT(1)은 boolean이 되나요?
열의 모든 값이 0 또는 1일 때만 bit가 돼요. 2나 -1 같은 다른 숫자가 있으면 숫자로 남고 보고서에 이유가 나와요. 그래서 실수로 1이 되는 값은 없어요.
저장 프로시저와 트리거는 어떻게 되나요?
데이터베이스마다 자체 언어로 작성하므로 변환하지 않고 보고서에 이름으로 나열해요. 예외는 ON UPDATE CURRENT_TIMESTAMP로, SQL Server 트리거가 돼요.
스크립트는 어떤 SQL Server 버전에서 불러올 수 있나요?
SQL Server 2017부터 2025까지예요. 모든 버전에서 같은 스크립트를 불러올 수 있고, 문제가 생기면 첫 오류에서 멈춰요.