MariaDB에서 SQLite로 변환
mariadb-dump, mysqldump, phpMyAdmin, Adminer로 만든 .sql 또는 .sql.gz 덤프를 놓으면, 같은 테이블, 키, 인덱스, 데이터를 담은 SQLite 스크립트를 다운로드할 수 있어요. SQLite이(가) 그대로 담을 수 없는 값과 옮기지 않는 객체는 모두 보고서에 나와요.
18개 행 변환, 수정 8개, 거부 없음
shop_2024_mariadb.sql의 테이블MariaDB 11.8.9-MariaDB-ubu2404 덤프 · mariadb-dump(으)로 작성됨 · utf8mb4
customers8개 행3
8개 열 id INTEGER not null name VARCHAR(100) not null email VARCHAR(150) not null country VARCHAR(2) not null is_active INTEGER not null signed_up DATE created_at TIMESTAMP not null last_ip TEXT orders10개 행5
12개 열 id INTEGER not null customer_id INTEGER not null status TEXT not null total DECIMAL(10,2) not null items INTEGER not null ordered_at DATETIME not null shipped_at DATETIME note VARCHAR(255) order_ref TEXT not null invoice INTEGER not null details TEXT updated_at TIMESTAMP not null
-- Written by IntoSQL from a MySQL dump. Load it with: sqlite3 -bail <database> < <file>
PRAGMA foreign_keys = OFF;
PRAGMA synchronous = OFF;
BEGIN;
CREATE TABLE customers ( -- People who bought at least once
id INTEGER PRIMARY KEY AUTOINCREMENT,
name VARCHAR(100) NOT NULL,
email VARCHAR(150) NOT NULL,
country VARCHAR(2) DEFAULT 'US' NOT NULL,
is_active INTEGER DEFAULT 1 NOT NULL,
signed_up DATE,
created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP NOT NULL,
last_ip TEXT,
CONSTRAINT customers_id_check CHECK (id >= 0)
);
CREATE TABLE orders (
id INTEGER PRIMARY KEY AUTOINCREMENT,
customer_id INTEGER NOT NULL,
status TEXT DEFAULT 'pending' NOT NULL,
total DECIMAL(10,2) NOT NULL,
items INTEGER DEFAULT 1 NOT NULL,
ordered_at DATETIME NOT NULL,
shipped_at DATETIME,
note VARCHAR(255),
order_ref TEXT NOT NULL,
invoice INTEGER NOT NULL,
details TEXT,
updated_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP NOT NULL,
CONSTRAINT orders_id_check CHECK (id >= 0),
CONSTRAINT orders_customer_id_check CHECK (customer_id >= 0),
CONSTRAINT orders_status_check CHECK (status IN ('pending', 'paid', 'shipped', 'cancelled', '')),
CONSTRAINT orders_items_check CHECK (items >= 0),
CONSTRAINT fk_orders_customer FOREIGN KEY (customer_id) REFERENCES customers (id)
);
INSERT INTO customers (id, name, email, country, is_active, signed_up, created_at, last_ip) VALUES
(1,'Ana Martínez','ana@example.com','MX',1,'2023-01-15','2023-01-15 10:24:00','::ffff:203.0.113.7'),
(2,'Zoë Müller','zoe@example.de','DE',1,'2023-02-03','2023-02-03 08:11:42','2001:db8::1'),
(3,'José Peña','jose@example.es','ES',0,'2023-03-21','2023-03-21 19:05:17',NULL),
(4,'李雷','lilei@example.cn','CN',1,'2023-05-09','2023-05-09 02:40:00','::ffff:198.51.100.23'),
(5,'Noah O''Brien','noah@example.ie','IE',1,NULL,'2023-06-30 14:00:00',NULL),
(6,'Amélie Laurent','amelie@example.fr','FR',1,'2024-01-02','2024-01-02 09:30:00','2001:db8:85a3::8a2e:370:7334'),
(7,'Ravi Patel','ravi@example.in','IN',0,'2024-02-29','2024-02-29 23:59:59','::ffff:192.0.2.200'),
(8,'Sofia Rossi 🌻','sofia@example.it','IT',1,'2024-04-12','2024-04-12 12:12:12',NULL);
INSERT INTO orders (id, customer_id, status, total, items, ordered_at, shipped_at, note, order_ref, invoice, details, updated_at) VALUES
(1,1,'shipped',129.90,3,'2024-03-01 10:00:00','2024-03-02 16:30:00',NULL,'0b7a4c2e-3f1d-4e8a-9c55-1a2b3c4d5e6f',1000,'{"gift": false}','2024-03-02 16:30:00'),
(2,2,'paid',54.00,1,'2024-03-02 11:15:00',NULL,'Gift wrap 🎁','1c8b5d3f-4a2e-4f9b-8d66-2b3c4d5e6f70',1001,'{"gift": true, "wrap": "red"}','2024-03-02 11:20:00'),
(3,1,'cancelled',12.50,1,'2024-03-03 09:45:00',NULL,'Customer changed their mind','2d9c6e4a-5b3f-4a0c-9e77-3c4d5e6f7081',1002,NULL,'2024-03-03 10:00:00'),
(4,4,'shipped',980.00,12,'2024-03-05 02:10:00','2024-03-07 08:00:00','请小心轻放','3e0d7f5b-6c4a-4b1d-8f88-4d5e6f708192',1003,'{"fragile": true}','2024-03-07 08:00:00'),
(5,5,'pending',45.75,2,'2024-03-08 17:20:00',NULL,'Leave at the door; ring twice','4f1e806c-7d5b-4c2e-9a99-5e6f708192a3',1004,NULL,'2024-03-08 17:20:00'),
(6,6,'shipped',310.40,5,'2024-03-10 13:00:00','2024-03-11 09:00:00','Fragile: "glass"','50f2917d-8e6c-4d3f-8baa-6f708192a3b4',1005,'{"fragile": true}','2024-03-11 09:00:00'),
(7,8,'paid',76.20,2,'2024-03-11 18:45:00',NULL,NULL,'6103a28e-9f7d-4e40-9cbb-708192a3b4c5',1006,NULL,'2024-03-11 18:46:00'),
(8,2,'',19.99,1,'2024-03-12 08:00:00',NULL,'Status lost in an old import','7214b39f-a08e-4f51-8dcc-8192a3b4c5d6',1007,NULL,'2024-03-12 08:00:00'),
(9,3,'shipped',64.00,2,'2024-03-14 15:30:00',NULL,'Shipping date never recorded','8325c4a0-b19f-4062-9edd-92a3b4c5d6e7',1008,'{"parcels": [1, 2]}','2024-03-15 10:00:00'),
(10,7,'paid',1499.00,1,'2024-03-15 21:05:00',NULL,'C:\Users\ravi\invoice.pdf','9436d5b1-c2a0-4173-8fee-a3b4c5d6e7f8',1009,NULL,'2024-03-15 21:05:00');
-- Indexes, triggers and counters, after the rows so each index builds once.
CREATE UNIQUE INDEX customers_uq_email ON customers (email);
CREATE INDEX orders_idx_customer ON orders (customer_id);
CREATE INDEX orders_idx_status_date ON orders (status, ordered_at);
UPDATE sqlite_sequence SET seq = max(seq, 1000) WHERE name = 'customers';
INSERT INTO sqlite_sequence (name, seq) SELECT 'customers', 1000 WHERE NOT EXISTS (SELECT 1 FROM sqlite_sequence WHERE name = 'customers');
UPDATE sqlite_sequence SET seq = max(seq, 5000) WHERE name = 'orders';
INSERT INTO sqlite_sequence (name, seq) SELECT 'orders', 5000 WHERE NOT EXISTS (SELECT 1 FROM sqlite_sequence WHERE name = 'orders');
CREATE TRIGGER orders_updated_at_on_update AFTER UPDATE ON orders FOR EACH ROW WHEN NEW.updated_at IS OLD.updated_at AND (NEW.id IS NOT OLD.id OR NEW.customer_id IS NOT OLD.customer_id OR NEW.status IS NOT OLD.status OR NEW.total IS NOT OLD.total OR NEW.items IS NOT OLD.items OR NEW.ordered_at IS NOT OLD.ordered_at OR NEW.shipped_at IS NOT OLD.shipped_at OR NEW.note IS NOT OLD.note OR NEW.order_ref IS NOT OLD.order_ref OR NEW.invoice IS NOT OLD.invoice OR NEW.details IS NOT OLD.details)
BEGIN
UPDATE orders SET updated_at = CURRENT_TIMESTAMP WHERE rowid = NEW.rowid;
END;
COMMIT;
-- Rows whose foreign key finds no parent, if any: the load doesn't stop for them.
PRAGMA foreign_key_check;
수정 사항
- customers의 "id" 열은 부호가 없어서, 음수가 아닌지 확인하는 체크 제약과 함께 INTEGER(으)로 만들었어요.
- customers의 "signed_up" 열은 이제 NULL을 허용해요. 일부 값을 저장할 수 없어 NULL이 됐어요.
- customers의 "signed_up" 열 기본값 0000‑00‑00은(는) SQLite이 받는 날짜가 아니라서 기본값을 없앴어요.
- orders의 "customer_id" 열은 부호가 없어서, 음수가 아닌지 확인하는 체크 제약과 함께 INTEGER(으)로 만들었어요.
- orders의 "id" 열은 부호가 없어서, 음수가 아닌지 확인하는 체크 제약과 함께 INTEGER(으)로 만들었어요.
- orders의 "items" 열은 부호가 없어서, 음수가 아닌지 확인하는 체크 제약과 함께 INTEGER(으)로 만들었어요.
- orders의 "status" 열에서 1개 행에 MySQL이 잘못된 입력에 저장하는 빈 값이 있어요. 값 체크 제약이 이 값을 허용해요.
- orders의 "updated_at" 열은 업데이트할 때마다 현재 시간으로 바뀌어요. SQLite에서는 트리거가 이를 처리해요.
확인 필요
- 1개 시퀀스를 만들지 않아요. SQLite에는 시퀀스가 없어요. 애플리케이션에 필요하면 다음 값을 테이블에 보관하세요.
- customers의 "signed_up" 열에 있는 1개 값은 0000‑00‑00 같은 0 날짜나 불가능한 날짜예요. SQLite이 저장할 수 없어 NULL로 두었어요. 이 날짜에 의미가 있다면 덤프하기 전에 원본에서 실제 날짜로 바꾸세요.
- orders의 "invoice" 열 기본값을 SQLite용으로 쓸 수 없어(a sequence) 기본값 없이 만들었어요. 새 행에 필요하면 기본값을 직접 추가하세요.
- orders의 "shipped_at" 열에 있는 1개 값은 0000‑00‑00 00:00:00 같은 0 날짜나 불가능한 날짜예요. SQLite이 저장할 수 없어 NULL로 두었어요. 이 날짜에 의미가 있다면 덤프하기 전에 원본에서 실제 날짜로 바꾸세요.
파일은 이 컴퓨터에서 변환되고 업로드되지 않아요.
다른 샘플:
MariaDB에서 SQLite로 바뀌는 점
각 행은 변환기가 적용하는 규칙이며, 규칙이 데이터를 바꿀 때 보고서에 쓰는 줄이 함께 나와요.
TINYINT(1), BOOL
값을 그대로 담은 INTEGER
SQLite에는 boolean 타입이 없고 true와 false는 정수 1과 0이라서, 모든 값이 의미를 유지해요.
UNSIGNED integers
음수가 아닌지 확인하는 CHECK가 붙은 INTEGER. 2^63-1보다 큰 값이 있는 BIGINT UNSIGNED는 TEXT
SQLite 정수는 64비트 부호 있는 정수예요. 체크 제약이 MySQL처럼 음수를 막고, 부호 있는 범위를 넘는 값은 자릿수를 잃지 않도록 텍스트로 유지해요.
보고서 줄: unsigned_widened
ZEROFILL and display widths
제거
0 채움은 숫자를 표시하는 방식일 뿐 숫자의 일부가 아니에요. 숫자는 유지되며, 채움이 필요하면 읽을 때 형식을 지정하세요.
보고서 줄: zerofill_dropped
FLOAT(M,D)
REAL, 소수 자릿수 없이
SQLite 부동소수점에는 고정 소수 자릿수가 없어요. 저장된 값은 그대로 복사돼요.
보고서 줄: float_scale_dropped
DECIMAL(p,s)
15자리까지는 DECIMAL(p,s), 그 이상은 TEXT
SQLite는 숫자에 유효 자릿수를 약 15자리까지 담아요. 더 넓은 소수는 모든 자릿수가 정확하도록 텍스트로 유지해요.
보고서 줄: decimal_as_text
BIT(1), BIT(n)
비트 값을 담은 INTEGER. BIT(64)는 TEXT 숫자로
비트 필드는 비트가 만드는 숫자로 저장해요. BIT(64)의 최상위 비트는 부호 있는 정수에 들어가지 않아서 그 숫자는 텍스트로 유지해요.
zero, partial or impossible dates (0000-00-00, 2024-02-30)
NULL
SQLite의 날짜 함수는 실제 달력 날짜만 읽어요. 이 값은 NULL이 되고, 다른 모든 데이터베이스처럼 보고서에 개수가 나와요.
보고서 줄: invalid_date_null
NOT NULL columns with values that become NULL
NOT NULL 제거
값을 NULL로 바꿔야 했던 열은 NOT NULL을 유지할 수 없어요. 유지하면 불러오기가 멈춰요.
보고서 줄: not_null_relaxed
DEFAULT '0000-00-00'
기본값 없음
실제 날짜가 아닌 기본값은 지어낸 날짜로 바꾸지 않고 제외해요.
보고서 줄: zero_date_default
TIME
MySQL이 쓰는 그대로의 TIME 텍스트, 기간 포함
SQLite는 시간을 텍스트로 담으므로 하루를 넘거나 음수인 기간도 정확히 유지돼요.
YEAR
범위 CHECK가 붙은 INTEGER
SQLite에는 연도 타입이 없어요. 체크 제약이 MySQL이 허용하는 값과 같은 값만 받아요.
CHAR(n), VARCHAR(n)
VARCHAR(n), 길이는 강제하지 않음
SQLite는 도구가 읽을 수 있도록 선언된 타입을 유지하지만 길이는 제한하지 않아요. 값은 MySQL이 돌려주는 값과 같아요.
DATETIME
ISO 8601 텍스트로 된 DATETIME
SQLite는 날짜를 날짜 함수가 읽는 텍스트로 저장해요.
TIMESTAMP
UTC 기준 ISO 8601 텍스트로 된 TIMESTAMP. 덤프에 명시된 시간대, 명시가 없으면 UTC
TIMESTAMP는 한 시점이며 UTC로 써요. 덤프는 기록한 시간대를 명시해요(mysqldump는 UTC로 기록해요). 명시가 없으면 값을 UTC로 읽고 보고서에 그렇게 적어요.
보고서 줄: timestamp_zone_assumed
ENUM
값 CHECK가 붙은 TEXT
체크 제약이 있는 텍스트는 같은 값을 유지해요.
ENUM holding '' (MySQL's error value)
체크 제약이 허용하는 빈 값
느슨한 SQL 모드에서 ENUM에 잘못된 값이 들어가면 MySQL은 빈 문자열을 저장해요. 이 행은 유지되고 체크 제약이 이를 허용해요.
보고서 줄: enum_invalid_value
ENUM holding values outside its list
CHECK 없음
목록에 없는 값은 체크 제약에 걸리므로 체크 제약을 만들지 않아요.
보고서 줄: enum_check_skipped
SET
MySQL이 쓰는 그대로의 TEXT('a,b')
SQLite에는 배열이 없어요. 텍스트는 MySQL이 돌려주는 값과 같아요.
JSON
TEXT
SQLite의 JSON 함수는 텍스트에서 JSON을 읽어요. JSON으로 선언한 열은 "123"을 숫자로 바꾸므로 TEXT로 만들어요.
NUL bytes in text
유지
SQLite 텍스트는 NUL 바이트를 담을 수 있어서 값을 그대로 복사해요.
text that isn't valid in its character set
잘못된 바이트를 대체 문자로
SQLite 텍스트는 UTF-8이에요. UTF-8이 아닌 바이트는 함수가 잘못 읽어요.
보고서 줄: invalid_utf8_replaced
text decoded twice (ñ)
그대로 복사
덤프에 정확히 이 문자들이 있으므로 그대로 복사하고, 보고서에서 알려 줘요.
보고서 줄: mojibake_suspected
AUTO_INCREMENT
INTEGER PRIMARY KEY AUTOINCREMENT, 카운터는 복사된 id 다음부터
SQLite는 정수 기본 키 전체에 번호를 매겨요. AUTOINCREMENT는 MySQL처럼 id가 재사용되지 않게 하고, 카운터는 가장 큰 id와 덤프의 AUTO_INCREMENT 중 더 큰 값 다음부터 이어져요.
AUTO_INCREMENT on part of a key or outside one
카운터 없는 INTEGER
SQLite는 기본 키 전체인 열에만 번호를 매기므로, 열은 값을 유지하고 새 행은 직접 값을 넣어야 해요.
보고서 줄: identity_without_counter
ON UPDATE CURRENT_TIMESTAMP
AFTER UPDATE 트리거
행이 바뀌었는데 업데이트에서 열을 지정하지 않으면, 트리거가 MySQL처럼 열을 현재 시간으로 설정해요.
보고서 줄: on_update_trigger
generated columns
GENERATED ALWAYS AS, 원본과 같은 VIRTUAL 또는 STORED
SQLite 3.31 이상은 생성 열을 같은 두 가지 방식으로 계산해요.
generated columns with functions SQLite lacks
일반 열
SQLite용으로 쓸 수 없는 수식은 일반 열로 남고 보고서에 한 줄 기록돼요.
보고서 줄: generated_not_translated
INVISIBLE columns
일반 열
SQLite에는 보이지 않는 열이 없어요.
보고서 줄: invisible_column
CHECK constraints
변환해서 CREATE TABLE 안에 인라인으로
SQLite는 CREATE TABLE 안에서만 체크 제약을 받아요.
CHECK constraints with functions SQLite lacks
만들지 않음
SQLite용으로 쓸 수 없는 체크 제약은 제외하고 보고해요.
보고서 줄: check_skipped
CHECK ... NOT ENFORCED
만들지 않음
MySQL은 이 체크 제약을 적용하지 않고 보관만 하므로, 행이 제약을 어길 수 있어요.
보고서 줄: check_not_enforced
defaults with functions SQLite lacks
기본값 없음
SQLite용으로 쓸 수 없는 기본값은 제외하고 보고해요.
보고서 줄: default_not_translated
keys and indexes on a prefix, c(20)
substr(c, 1, 20) 인덱스
SQLite는 식을 인덱싱하므로 같은 접두부를 인덱싱하고, 고유한 접두부는 고유하게 유지돼요.
보고서 줄: prefix_unique
FULLTEXT indexes
만들지 않음
SQLite는 별도의 FTS5 테이블로 텍스트를 검색하며, 전용 쿼리가 필요해요.
보고서 줄: fulltext_not_created
SPATIAL indexes
만들지 않음
SQLite에는 열에 대한 공간 인덱스가 없어요.
보고서 줄: spatial_index_not_created
functional indexes SQLite can't write
만들지 않음
SQLite용으로 쓸 수 없는 식에 대한 인덱스는 제외하고 보고해요.
보고서 줄: index_skipped
foreign keys
CREATE TABLE 안에 두고, 검사 없이 불러온 뒤 PRAGMA foreign_key_check로 나열
SQLite는 외래 키를 CREATE TABLE 안에서만 받고, PRAGMA foreign_keys가 켜져 있을 때만 검사해요. 행은 MySQL에서처럼 검사 없이 불러오고, 스크립트 끝에서 부모 없는 행을 나열해요.
foreign keys to columns without a unique key
만들지 않음
SQLite는 참조되는 열에 고유 키가 필요하지만 InnoDB는 그렇지 않아요.
보고서 줄: foreign_key_skipped
table, index and column names
쓴 그대로. 대소문자만 다르거나 인덱스 이름이 겹치면 이름 변경
SQLite 이름은 대소문자를 구분하지 않고, 인덱스 이름은 데이터베이스마다 하나의 네임스페이스를 공유해요.
보고서 줄: identifier_renamed
GEOMETRY, POINT, POLYGON...
BLOB에 WKB로
표준 WKB(well-known binary)가 모든 지오메트리를 정확히 유지해요.
보고서 줄: geometry_as_blob
INET4, INET6, UUID (MariaDB)
TEXT
SQLite에는 이런 타입이 없어요. 텍스트는 MariaDB가 돌려주는 값과 같아요.
BINARY, VARBINARY, BLOB
BLOB
바이트는 바이트 그대로 남아요.
PARTITION BY
하나의 테이블
행은 같아요.
보고서 줄: partitions_dropped
WITH SYSTEM VERSIONING (MariaDB)
현재 행만 담은 테이블
덤프에는 현재 행만 들어 있어요.
보고서 줄: system_versioning_dropped
MyISAM, MEMORY and other engines
일반 테이블
SQLite의 테이블 엔진은 하나예요.
보고서 줄: engine_dropped
dumps of several databases
하나의 파일, 각 테이블 이름 앞에 데이터베이스 이름
SQLite 파일은 하나의 데이터베이스라서, 데이터베이스 이름으로 이름이 같은 테이블을 구분해요.
보고서 줄: databases_merged
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
BLOB에 WKB로
MySQL의 지오메트리 형식을 값에서 알아보고 표준 WKB로 저장해요.
보고서 줄: geometry_as_blob
_ci collations
정확한 비교
SQLite는 따로 지정하지 않으면 텍스트를 정확히 비교하고, NOCASE는 ASCII 문자만 대소문자를 무시해요.
보고서 줄: case_insensitive_collation
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
TEXT
텍스트는 어떤 값이든 담아요. 불러온 뒤 타입을 바꾸세요.
보고서 줄: unknown_type
values that don't fit their column
NULL
손상되었거나 직접 작성한 덤프에는 열이 담을 수 없는 값이 있을 수 있어요. 나머지를 불러올 수 있도록 이 값은 NULL이 돼요.
보고서 줄: invalid_value_null
unreadable geometries
NULL
지오메트리가 아닌 바이트는 지오메트리로 저장할 수 없어요.
보고서 줄: bad_geometry
CREATE SEQUENCE (MariaDB)
만들지 않음
SQLite에는 시퀀스가 없어요.
보고서 줄: sequence_not_converted
VECTOR(n) (MariaDB 11.7+)
부동소수점 값을 JSON 배열로 담은 TEXT
SQLite에는 vector 타입이 없어요. JSON 배열은 모든 부동소수점 값을 유지해요.
보고서 줄: type_replaced
| MariaDB에서 | SQLite에서 | 보고서 줄 |
|---|---|---|
| TINYINT(1), BOOL | 값을 그대로 담은 INTEGERSQLite에는 boolean 타입이 없고 true와 false는 정수 1과 0이라서, 모든 값이 의미를 유지해요. | |
| UNSIGNED integers | 음수가 아닌지 확인하는 CHECK가 붙은 INTEGER. 2^63-1보다 큰 값이 있는 BIGINT UNSIGNED는 TEXTSQLite 정수는 64비트 부호 있는 정수예요. 체크 제약이 MySQL처럼 음수를 막고, 부호 있는 범위를 넘는 값은 자릿수를 잃지 않도록 텍스트로 유지해요. | unsigned_widened |
| ZEROFILL and display widths | 제거0 채움은 숫자를 표시하는 방식일 뿐 숫자의 일부가 아니에요. 숫자는 유지되며, 채움이 필요하면 읽을 때 형식을 지정하세요. | zerofill_dropped |
| FLOAT(M,D) | REAL, 소수 자릿수 없이SQLite 부동소수점에는 고정 소수 자릿수가 없어요. 저장된 값은 그대로 복사돼요. | float_scale_dropped |
| DECIMAL(p,s) | 15자리까지는 DECIMAL(p,s), 그 이상은 TEXTSQLite는 숫자에 유효 자릿수를 약 15자리까지 담아요. 더 넓은 소수는 모든 자릿수가 정확하도록 텍스트로 유지해요. | decimal_as_text |
| BIT(1), BIT(n) | 비트 값을 담은 INTEGER. BIT(64)는 TEXT 숫자로비트 필드는 비트가 만드는 숫자로 저장해요. BIT(64)의 최상위 비트는 부호 있는 정수에 들어가지 않아서 그 숫자는 텍스트로 유지해요. | |
| zero, partial or impossible dates (0000-00-00, 2024-02-30) | NULLSQLite의 날짜 함수는 실제 달력 날짜만 읽어요. 이 값은 NULL이 되고, 다른 모든 데이터베이스처럼 보고서에 개수가 나와요. | invalid_date_null |
| NOT NULL columns with values that become NULL | NOT NULL 제거값을 NULL로 바꿔야 했던 열은 NOT NULL을 유지할 수 없어요. 유지하면 불러오기가 멈춰요. | not_null_relaxed |
| DEFAULT '0000-00-00' | 기본값 없음실제 날짜가 아닌 기본값은 지어낸 날짜로 바꾸지 않고 제외해요. | zero_date_default |
| TIME | MySQL이 쓰는 그대로의 TIME 텍스트, 기간 포함SQLite는 시간을 텍스트로 담으므로 하루를 넘거나 음수인 기간도 정확히 유지돼요. | |
| YEAR | 범위 CHECK가 붙은 INTEGERSQLite에는 연도 타입이 없어요. 체크 제약이 MySQL이 허용하는 값과 같은 값만 받아요. | |
| CHAR(n), VARCHAR(n) | VARCHAR(n), 길이는 강제하지 않음SQLite는 도구가 읽을 수 있도록 선언된 타입을 유지하지만 길이는 제한하지 않아요. 값은 MySQL이 돌려주는 값과 같아요. | |
| DATETIME | ISO 8601 텍스트로 된 DATETIMESQLite는 날짜를 날짜 함수가 읽는 텍스트로 저장해요. | |
| TIMESTAMP | UTC 기준 ISO 8601 텍스트로 된 TIMESTAMP. 덤프에 명시된 시간대, 명시가 없으면 UTCTIMESTAMP는 한 시점이며 UTC로 써요. 덤프는 기록한 시간대를 명시해요(mysqldump는 UTC로 기록해요). 명시가 없으면 값을 UTC로 읽고 보고서에 그렇게 적어요. | timestamp_zone_assumed |
| ENUM | 값 CHECK가 붙은 TEXT체크 제약이 있는 텍스트는 같은 값을 유지해요. | |
| ENUM holding '' (MySQL's error value) | 체크 제약이 허용하는 빈 값느슨한 SQL 모드에서 ENUM에 잘못된 값이 들어가면 MySQL은 빈 문자열을 저장해요. 이 행은 유지되고 체크 제약이 이를 허용해요. | enum_invalid_value |
| ENUM holding values outside its list | CHECK 없음목록에 없는 값은 체크 제약에 걸리므로 체크 제약을 만들지 않아요. | enum_check_skipped |
| SET | MySQL이 쓰는 그대로의 TEXT('a,b')SQLite에는 배열이 없어요. 텍스트는 MySQL이 돌려주는 값과 같아요. | |
| JSON | TEXTSQLite의 JSON 함수는 텍스트에서 JSON을 읽어요. JSON으로 선언한 열은 "123"을 숫자로 바꾸므로 TEXT로 만들어요. | |
| NUL bytes in text | 유지SQLite 텍스트는 NUL 바이트를 담을 수 있어서 값을 그대로 복사해요. | |
| text that isn't valid in its character set | 잘못된 바이트를 대체 문자로SQLite 텍스트는 UTF-8이에요. UTF-8이 아닌 바이트는 함수가 잘못 읽어요. | invalid_utf8_replaced |
| text decoded twice (ñ) | 그대로 복사덤프에 정확히 이 문자들이 있으므로 그대로 복사하고, 보고서에서 알려 줘요. | mojibake_suspected |
| AUTO_INCREMENT | INTEGER PRIMARY KEY AUTOINCREMENT, 카운터는 복사된 id 다음부터SQLite는 정수 기본 키 전체에 번호를 매겨요. AUTOINCREMENT는 MySQL처럼 id가 재사용되지 않게 하고, 카운터는 가장 큰 id와 덤프의 AUTO_INCREMENT 중 더 큰 값 다음부터 이어져요. | |
| AUTO_INCREMENT on part of a key or outside one | 카운터 없는 INTEGERSQLite는 기본 키 전체인 열에만 번호를 매기므로, 열은 값을 유지하고 새 행은 직접 값을 넣어야 해요. | identity_without_counter |
| ON UPDATE CURRENT_TIMESTAMP | AFTER UPDATE 트리거행이 바뀌었는데 업데이트에서 열을 지정하지 않으면, 트리거가 MySQL처럼 열을 현재 시간으로 설정해요. | on_update_trigger |
| generated columns | GENERATED ALWAYS AS, 원본과 같은 VIRTUAL 또는 STOREDSQLite 3.31 이상은 생성 열을 같은 두 가지 방식으로 계산해요. | |
| generated columns with functions SQLite lacks | 일반 열SQLite용으로 쓸 수 없는 수식은 일반 열로 남고 보고서에 한 줄 기록돼요. | generated_not_translated |
| INVISIBLE columns | 일반 열SQLite에는 보이지 않는 열이 없어요. | invisible_column |
| CHECK constraints | 변환해서 CREATE TABLE 안에 인라인으로SQLite는 CREATE TABLE 안에서만 체크 제약을 받아요. | |
| CHECK constraints with functions SQLite lacks | 만들지 않음SQLite용으로 쓸 수 없는 체크 제약은 제외하고 보고해요. | check_skipped |
| CHECK ... NOT ENFORCED | 만들지 않음MySQL은 이 체크 제약을 적용하지 않고 보관만 하므로, 행이 제약을 어길 수 있어요. | check_not_enforced |
| defaults with functions SQLite lacks | 기본값 없음SQLite용으로 쓸 수 없는 기본값은 제외하고 보고해요. | default_not_translated |
| keys and indexes on a prefix, c(20) | substr(c, 1, 20) 인덱스SQLite는 식을 인덱싱하므로 같은 접두부를 인덱싱하고, 고유한 접두부는 고유하게 유지돼요. | prefix_unique |
| FULLTEXT indexes | 만들지 않음SQLite는 별도의 FTS5 테이블로 텍스트를 검색하며, 전용 쿼리가 필요해요. | fulltext_not_created |
| SPATIAL indexes | 만들지 않음SQLite에는 열에 대한 공간 인덱스가 없어요. | spatial_index_not_created |
| functional indexes SQLite can't write | 만들지 않음SQLite용으로 쓸 수 없는 식에 대한 인덱스는 제외하고 보고해요. | index_skipped |
| foreign keys | CREATE TABLE 안에 두고, 검사 없이 불러온 뒤 PRAGMA foreign_key_check로 나열SQLite는 외래 키를 CREATE TABLE 안에서만 받고, PRAGMA foreign_keys가 켜져 있을 때만 검사해요. 행은 MySQL에서처럼 검사 없이 불러오고, 스크립트 끝에서 부모 없는 행을 나열해요. | |
| foreign keys to columns without a unique key | 만들지 않음SQLite는 참조되는 열에 고유 키가 필요하지만 InnoDB는 그렇지 않아요. | foreign_key_skipped |
| table, index and column names | 쓴 그대로. 대소문자만 다르거나 인덱스 이름이 겹치면 이름 변경SQLite 이름은 대소문자를 구분하지 않고, 인덱스 이름은 데이터베이스마다 하나의 네임스페이스를 공유해요. | identifier_renamed |
| GEOMETRY, POINT, POLYGON... | BLOB에 WKB로표준 WKB(well-known binary)가 모든 지오메트리를 정확히 유지해요. | geometry_as_blob |
| INET4, INET6, UUID (MariaDB) | TEXTSQLite에는 이런 타입이 없어요. 텍스트는 MariaDB가 돌려주는 값과 같아요. | |
| BINARY, VARBINARY, BLOB | BLOB바이트는 바이트 그대로 남아요. | |
| PARTITION BY | 하나의 테이블행은 같아요. | partitions_dropped |
| WITH SYSTEM VERSIONING (MariaDB) | 현재 행만 담은 테이블덤프에는 현재 행만 들어 있어요. | system_versioning_dropped |
| MyISAM, MEMORY and other engines | 일반 테이블SQLite의 테이블 엔진은 하나예요. | engine_dropped |
| dumps of several databases | 하나의 파일, 각 테이블 이름 앞에 데이터베이스 이름SQLite 파일은 하나의 데이터베이스라서, 데이터베이스 이름으로 이름이 같은 테이블을 구분해요. | databases_merged |
| 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 | BLOB에 WKB로MySQL의 지오메트리 형식을 값에서 알아보고 표준 WKB로 저장해요. | geometry_as_blob |
| _ci collations | 정확한 비교SQLite는 따로 지정하지 않으면 텍스트를 정확히 비교하고, NOCASE는 ASCII 문자만 대소문자를 무시해요. | case_insensitive_collation |
| 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 | TEXT텍스트는 어떤 값이든 담아요. 불러온 뒤 타입을 바꾸세요. | unknown_type |
| values that don't fit their column | NULL손상되었거나 직접 작성한 덤프에는 열이 담을 수 없는 값이 있을 수 있어요. 나머지를 불러올 수 있도록 이 값은 NULL이 돼요. | invalid_value_null |
| unreadable geometries | NULL지오메트리가 아닌 바이트는 지오메트리로 저장할 수 없어요. | bad_geometry |
| CREATE SEQUENCE (MariaDB) | 만들지 않음SQLite에는 시퀀스가 없어요. | sequence_not_converted |
| VECTOR(n) (MariaDB 11.7+) | 부동소수점 값을 JSON 배열로 담은 TEXTSQLite에는 vector 타입이 없어요. JSON 배열은 모든 부동소수점 값을 유지해요. | type_replaced |
스크립트를 SQLite에 불러오기
스크립트는 테이블을 만들고 행을 복사한 다음 키, 인덱스, 외래 키를 추가해요. 그래서 빨리 불러오고 첫 오류에서 멈춰요.
sqlite3 -bail mydb.sqlite < mariadb.sqlite.sql외래 키는 각 테이블 안에 선언하고, 행은 외래 키 검사를 끈 채로 불러와요. 그런 다음 스크립트는 중간에 실패하지 않고, 존재하지 않는 행을 가리키는 행을 모두 나열해요.
큰 덤프는 로컬 디스크의 새 파일로 불러오세요. 스크립트는 동기화를 끈 하나의 트랜잭션으로 모두 불러오므로 디스크 속도로 실행되고, 중간에 멈춰도 일부만 채워진 테이블이 남지 않아요.
명령줄은 파일을 SQLite 데이터베이스에 바로 불러와요. 스크립트를 따로 만들 필요가 없고 무료예요.
좋은 결과를 위한 MariaDB 덤프 방법
변환기는 덤프에 담긴 내용을 읽어요. 다음 옵션을 쓰면 더 많은 데이터가 덤프에 남아요:
- --default-character-set=utf8mb4는 이모지와 다른 4바이트 문자를 유지해요. utf8mb3 덤프는 변환기가 보기 전에 이 문자를 잃어요.
- --hex-blob은 바이너리 열과 VECTOR 값을 16진수로 써서, 시스템 사이에 복사해도 손상되지 않아요.
- --routines --triggers --events는 이 객체들을 덤프에 넣어 보고서가 나열할 수 있게 해요.
변환되지 않는 것
뷰, 트리거, 저장 프로시저, 함수, 이벤트는 MariaDB의 자체 언어로 작성돼요. 보고서에 이름으로 나열되고 몰래 빠지는 일은 없으므로, SQLite에 맞게 다시 작성할 수 있어요.
MariaDB에서 SQLite로 변환에 관한 질문
여기에 답이 없나요? 문의 페이지로 연락하시면 담당자가 답장해요. 문의 페이지
덤프가 업로드되나요?
아니요. 변환기는 브라우저에서 실행되고 디스크의 덤프를 조각조각 읽으므로, 덤프가 컴퓨터 밖으로 나가지 않아요. 데스크톱 앱과 명령줄도 컴퓨터에서 변환해요.
덤프는 얼마나 커도 되나요?
변환기는 덤프 전체를 메모리에 올리지 않아요. 파일을 범위별로 두 번 읽고, 읽는 대로 스크립트를 써요. 수 GB 덤프도 브라우저, 데스크톱 앱, 명령줄에서 변환돼요.
어떤 MariaDB 버전의 덤프를 읽나요?
MariaDB 10.3부터 12까지의 mariadb-dump와 mysqldump로 만든 덤프예요. INSERT는 테이블마다 하나여도 행마다 하나여도 돼요. 모든 테스트 덤프는 MariaDB 10.11, 11.4, 11.8에서 만들고 원본과 셀 단위로 비교해요.
UUID, INET6, JSON, VECTOR 열은 유지되나요?
UUID와 INET 열은 text, JSON은 text, VECTOR는 부동소수점 값의 JSON 배열이 돼요. 0 날짜는 NULL이 되고 보고서에 개수가 나와요.
AUTO_INCREMENT 값과 시퀀스는 유지되나요?
테이블의 기본 키 전체인 AUTO_INCREMENT 열은 INTEGER PRIMARY KEY AUTOINCREMENT가 되고 가장 큰 id 다음부터 이어져요. SQLite에는 시퀀스가 없으므로 시퀀스는 보고서에 나와요.
저장 프로시저와 트리거는 어떻게 되나요?
데이터베이스마다 자체 언어로 작성하므로 변환하지 않고 보고서에 이름으로 나열해요.
스크립트는 어떤 SQLite 버전에서 불러올 수 있나요?
SQLite 3.31 이상이에요. 모든 테스트 덤프를 3.31과 3.54에서 불러오며, 문제가 생기면 첫 오류에서 멈춰요.