Chuyển đến nội dung

Chuyển MySQL sang PostgreSQL

Thả bản dump từ mysqldump, mariadb-dump, mysqlpump, phpMyAdmin hoặc Adminer, dạng .sql hoặc .sql.gz, và tải xuống tập lệnh PostgreSQL với cùng bảng, khóa, chỉ mục và dữ liệu. Mọi giá trị PostgreSQL không chứa được nguyên trạng, và mọi đối tượng nó không hỗ trợ, đều được liệt kê trong báo cáo.

Tệp của bạn
sqlshop_2024.sqlTệp mẫu, 5,1 kB
Cơ sở dữ liệu của bạn

Đã chuyển đổi 18 hàng, 8 bản sửa, không hàng nào bị từ chối

Hiển thị

Các bảng trong shop_2024.sqlBản dump MySQL 8.0.46 · do mysqldump ghi · utf8mb4

  • customers8 hàng3
    7 cột
    idbigint not null
    namevarchar(100) not null
    emailvarchar(150) not null
    countryvarchar(2) not null
    is_activeboolean not null
    signed_update
    created_attimestamptz(0) not null
  • orders10 hàng5
    9 cột
    idbigint not null
    customer_idbigint not null
    statustext not null
    totalnumeric(10,2) not null
    itemsinteger not null
    ordered_attimestamp(0) not null
    shipped_attimestamp(0)
    notevarchar(255)
    updated_attimestamptz(0) not null
-- Written by IntoSQL from a MySQL dump. Load it with: psql -v ON_ERROR_STOP=1 -f <file>
SET client_encoding = 'UTF8';
SET standard_conforming_strings = on;
SET check_function_bodies = false;
SET client_min_messages = warning;
SET synchronous_commit = off;
SET maintenance_work_mem = '512MB';

CREATE TABLE customers (
    id bigint GENERATED BY DEFAULT AS IDENTITY NOT NULL,
    name varchar(100) NOT NULL,
    email varchar(150) NOT NULL,
    country varchar(2) DEFAULT 'US' NOT NULL,
    is_active boolean DEFAULT true NOT NULL,
    signed_up date,
    created_at timestamptz(0) DEFAULT CURRENT_TIMESTAMP NOT NULL,
    CONSTRAINT customers_id_check CHECK (id >= 0)
);

CREATE TABLE orders (
    id bigint GENERATED BY DEFAULT AS IDENTITY NOT NULL,
    customer_id bigint NOT NULL,
    status text DEFAULT 'pending' NOT NULL,
    total numeric(10,2) NOT NULL,
    items integer DEFAULT 1 NOT NULL,
    ordered_at timestamp(0) NOT NULL,
    shipped_at timestamp(0),
    note varchar(255),
    updated_at timestamptz(0) 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)
);

COPY customers (id, name, email, country, is_active, signed_up, created_at) FROM stdin;
1	Ana Martínez	ana@example.com	MX	t	2023-01-15	2023-01-15 10:24:00+00:00
2	Zoë Müller	zoe@example.de	DE	t	2023-02-03	2023-02-03 08:11:42+00:00
3	José Peña	jose@example.es	ES	f	2023-03-21	2023-03-21 19:05:17+00:00
4	李雷	lilei@example.cn	CN	t	2023-05-09	2023-05-09 02:40:00+00:00
5	Noah O'Brien	noah@example.ie	IE	t	\N	2023-06-30 14:00:00+00:00
6	Amélie Laurent	amelie@example.fr	FR	t	2024-01-02	2024-01-02 09:30:00+00:00
7	Ravi Patel	ravi@example.in	IN	f	2024-02-29	2024-02-29 23:59:59+00:00
8	Sofia Rossi 🌻	sofia@example.it	IT	t	2024-04-12	2024-04-12 12:12:12+00:00
\.

COPY orders (id, customer_id, status, total, items, ordered_at, shipped_at, note, updated_at) FROM stdin;
1	1	shipped	129.90	3	2024-03-01 10:00:00	2024-03-02 16:30:00	\N	2024-03-02 16:30:00+00:00
2	2	paid	54.00	1	2024-03-02 11:15:00	\N	Gift wrap 🎁	2024-03-02 11:20:00+00:00
3	1	cancelled	12.50	1	2024-03-03 09:45:00	\N	Customer changed their mind	2024-03-03 10:00:00+00:00
4	4	shipped	980.00	12	2024-03-05 02:10:00	2024-03-07 08:00:00	请小心轻放	2024-03-07 08:00:00+00:00
5	5	pending	45.75	2	2024-03-08 17:20:00	\N	Leave at the door; ring twice	2024-03-08 17:20:00+00:00
6	6	shipped	310.40	5	2024-03-10 13:00:00	2024-03-11 09:00:00	Fragile: "glass"	2024-03-11 09:00:00+00:00
7	8	paid	76.20	2	2024-03-11 18:45:00	\N	\N	2024-03-11 18:46:00+00:00
8	2		19.99	1	2024-03-12 08:00:00	\N	Status lost in an old import	2024-03-12 08:00:00+00:00
9	3	shipped	64.00	2	2024-03-14 15:30:00	\N	Shipping date never recorded	2024-03-15 10:00:00+00:00
10	7	paid	1499.00	1	2024-03-15 21:05:00	\N	C:\\Users\\ravi\\invoice.pdf	2024-03-15 21:05:00+00:00
\.


-- Keys, indexes and constraints, after the rows so each builds once.
CREATE UNIQUE INDEX customers_pkey ON customers (id);
CREATE UNIQUE INDEX customers_uq_email ON customers (email);
CREATE UNIQUE INDEX orders_pkey ON orders (id);
CREATE INDEX orders_idx_customer ON orders (customer_id);
CREATE INDEX orders_idx_status_date ON orders (status, ordered_at);
ALTER TABLE customers ADD CONSTRAINT customers_pkey PRIMARY KEY USING INDEX customers_pkey;
ALTER TABLE customers ADD CONSTRAINT customers_uq_email UNIQUE USING INDEX customers_uq_email;
ALTER TABLE orders ADD CONSTRAINT orders_pkey PRIMARY KEY USING INDEX orders_pkey;
ALTER TABLE orders ADD CONSTRAINT fk_orders_customer FOREIGN KEY (customer_id) REFERENCES customers (id) NOT VALID;
DO $f$ BEGIN
    ALTER TABLE orders VALIDATE CONSTRAINT fk_orders_customer;
EXCEPTION WHEN foreign_key_violation THEN
    RAISE WARNING 'foreign key % has rows without a parent: it stays NOT VALID, and new rows are checked', 'fk_orders_customer';
END $f$;
SELECT setval(pg_get_serial_sequence('customers', 'id'), LEAST(GREATEST(COALESCE((SELECT max(id) FROM customers)::numeric, 0) + 1, 1001), 9223372036854775807)::bigint, false);
COMMENT ON TABLE customers IS 'People who bought at least once';
SELECT setval(pg_get_serial_sequence('orders', 'id'), LEAST(GREATEST(COALESCE((SELECT max(id) FROM orders)::numeric, 0) + 1, 5001), 9223372036854775807)::bigint, false);
CREATE FUNCTION orders_updated_at_on_update() RETURNS trigger LANGUAGE plpgsql AS $f$
BEGIN
    IF NEW IS DISTINCT FROM OLD AND NEW.updated_at IS NOT DISTINCT FROM OLD.updated_at THEN
        NEW.updated_at := CURRENT_TIMESTAMP;
    END IF;
    RETURN NEW;
END
$f$;
CREATE TRIGGER orders_updated_at_on_update BEFORE UPDATE ON orders FOR EACH ROW EXECUTE FUNCTION orders_updated_at_on_update();

Bản sửa

  1. "id" của customers là số không dấu, nên được chuyển thành bigint kèm ràng buộc kiểm tra không âm.
  2. "signed_up" của customers giờ cho phép NULL: một số giá trị không lưu được và là NULL.
  3. Giá trị mặc định của "signed_up" trong customers, 0000‑00‑00, không phải ngày PostgreSQL chấp nhận, nên cột không có giá trị mặc định.
  4. "customer_id" của orders là số không dấu, nên được chuyển thành bigint kèm ràng buộc kiểm tra không âm.
  5. "id" của orders là số không dấu, nên được chuyển thành bigint kèm ràng buộc kiểm tra không âm.
  6. "items" của orders là số không dấu, nên được chuyển thành integer kèm ràng buộc kiểm tra không âm.
  7. 1 hàng của "status" trong orders chứa giá trị rỗng mà MySQL lưu cho mục không hợp lệ; ràng buộc kiểm tra giá trị cho phép giá trị này.
  8. "updated_at" của orders đổi thành thời điểm hiện tại mỗi lần cập nhật; trong PostgreSQL, một trình kích hoạt làm việc đó.

Cần xem lại

  • 1 giá trị trong "signed_up" của customers là ngày bằng 0 hoặc không hợp lệ, như 0000‑00‑00, mà PostgreSQL không lưu được, nên được đặt thành NULL. Nếu các ngày đó có ý nghĩa, hãy thay chúng bằng ngày thật trong nguồn trước khi tạo bản dump.
  • 1 giá trị trong "shipped_at" của orders là ngày bằng 0 hoặc không hợp lệ, như 0000‑00‑00 00:00:00, mà PostgreSQL không lưu được, nên được đặt thành NULL. Nếu các ngày đó có ý nghĩa, hãy thay chúng bằng ngày thật trong nguồn trước khi tạo bản dump.

Tệp được chuyển đổi ngay trên máy tính này và không bao giờ được tải lên.

Mẫu khác:

Những gì thay đổi từ MySQL sang PostgreSQL

Mỗi hàng là một quy tắc trình chuyển đổi áp dụng, kèm dòng báo cáo được ghi khi quy tắc thay đổi dữ liệu của bạn.

  • TINYINT(1), BOOL

    boolean khi mọi giá trị là 0 hoặc 1, nếu không thì smallint

    BOOL của MySQL là TINYINT(1), chứa được mọi số từ -128 đến 127. Cột chỉ chứa 0 và 1 trở thành boolean; cột chứa 2 hoặc -1 vẫn là số để không giá trị nào đổi nghĩa.

    Dòng báo cáo: bool_kept_numeric

  • UNSIGNED integers

    kiểu số nguyên rộng hơn kế tiếp kèm CHECK không âm; BIGINT UNSIGNED là bigint khi mọi giá trị vừa, nếu không thì numeric(20,0)

    PostgreSQL không có số nguyên không dấu. Kiểu rộng hơn chứa được toàn bộ dải không dấu, và ràng buộc kiểm tra chặn giá trị âm như MySQL.

    Dòng báo cáo: unsigned_widened

  • ZEROFILL and display widths

    bị bỏ

    Thêm số 0 phía trước là cách hiển thị số, không phải một phần của số. Các số được giữ; hãy định dạng khi đọc nếu cần phần số 0 đó.

    Dòng báo cáo: zerofill_dropped

  • FLOAT(M,D)

    real hoặc double precision, bỏ số chữ số thập phân cố định

    Số dấu phẩy động của PostgreSQL không có số chữ số thập phân cố định. Giá trị đã lưu được sao chép nguyên trạng.

    Dòng báo cáo: float_scale_dropped

  • BIT(1), BIT(n)

    boolean, bit(n)

    Một bit đơn là có hoặc không; trường bit rộng hơn giữ mọi bit.

  • zero, partial or impossible dates (0000-00-00, 2024-02-30)

    NULL

    PostgreSQL chỉ lưu ngày có thật trên lịch. MySQL giữ ngày bằng 0 và ngày không hợp lệ khi chế độ SQL cho phép; chúng trở thành NULL và báo cáo đếm số lượng.

    Dòng báo cáo: invalid_date_null

  • NOT NULL columns with values that become NULL

    bỏ NOT NULL

    Cột có giá trị phải chuyển thành NULL không thể giữ NOT NULL, nếu không quá trình nạp sẽ dừng.

    Dòng báo cáo: not_null_relaxed

  • DEFAULT '0000-00-00'

    không có giá trị mặc định

    Giá trị mặc định mà PostgreSQL không lưu được sẽ bị bỏ, thay vì thay bằng một ngày bịa ra.

    Dòng báo cáo: zero_date_default

  • TIME

    time khi mọi giá trị nằm trong một ngày, nếu không thì interval

    TIME của MySQL là khoảng thời gian từ -838:59:59 đến 838:59:59. Cột có giá trị nằm trong một ngày vẫn là giờ trong ngày; cột có giá trị dài hơn hoặc âm trở thành interval.

    Dòng báo cáo: time_as_interval

  • YEAR

    smallint kèm CHECK phạm vi

    PostgreSQL không có kiểu năm; ràng buộc kiểm tra giữ đúng các giá trị MySQL cho phép.

  • CHAR(n)

    varchar(n)

    MySQL bỏ khoảng trắng cuối của giá trị CHAR khi đọc, còn char(n) của PostgreSQL sẽ thêm lại, nên varchar(n) giữ giá trị đúng như MySQL trả về.

  • DATETIME

    timestamp

    DATETIME là thời gian theo đồng hồ, không kèm múi giờ, giống timestamp của PostgreSQL.

  • TIMESTAMP

    timestamptz theo múi giờ bản dump nêu, UTC khi không nêu

    TIMESTAMP là một thời điểm. Bản dump nêu múi giờ đã dùng khi ghi (mysqldump ghi UTC); nếu không, giá trị được đọc theo UTC và báo cáo ghi rõ điều đó.

    Dòng báo cáo: timestamp_zone_assumed

  • ENUM

    text kèm CHECK các giá trị

    Văn bản kèm ràng buộc kiểm tra giữ đúng các giá trị và dễ thay đổi hơn enum type của PostgreSQL.

  • ENUM holding '' (MySQL's error value)

    giá trị rỗng được ràng buộc kiểm tra cho phép

    MySQL lưu chuỗi rỗng khi một giá trị không hợp lệ được ghi vào ENUM ở chế độ SQL không nghiêm ngặt. Các hàng đó được giữ và ràng buộc kiểm tra cho phép chúng.

    Dòng báo cáo: enum_invalid_value

  • ENUM or SET holding values outside its list

    không có CHECK

    Giá trị không có trong danh sách sẽ vi phạm ràng buộc kiểm tra, nên ràng buộc không được tạo.

    Dòng báo cáo: enum_check_skipped

  • SET

    text[] kèm CHECK rằng mọi phần tử có trong danh sách

    Mảng giữ từng phần tử riêng, nên truy vấn có thể kiểm tra một phần tử có thuộc tập hợp không.

  • JSON

    jsonb; json khi một giá trị chứa \u0000

    jsonb là kiểu PostgreSQL lập chỉ mục và truy vấn tốt, nhưng nó từ chối chuỗi thoát \u0000, nên cột có chuỗi này vẫn là json.

    Dòng báo cáo: json_not_jsonb

  • NUL bytes in text

    bị xóa

    Văn bản PostgreSQL không chứa được byte NUL. Byte này bị xóa và báo cáo đếm các giá trị.

    Dòng báo cáo: nul_removed

  • text that isn't valid in its character set

    byte lỗi thành ký tự thay thế

    Văn bản PostgreSQL phải là UTF-8 hợp lệ.

    Dòng báo cáo: invalid_utf8_replaced

  • text decoded twice (ñ)

    sao chép nguyên trạng

    Bản dump chứa đúng các ký tự này, nên chúng được sao chép; báo cáo chỉ ra chúng.

    Dòng báo cáo: mojibake_suspected

  • AUTO_INCREMENT

    GENERATED BY DEFAULT AS IDENTITY, bộ đếm đặt sau các id đã sao chép

    Cột identity nhận các id đã sao chép, và bộ đếm tiếp tục sau id lớn nhất hoặc AUTO_INCREMENT của bản dump, tùy giá trị nào lớn hơn.

  • MyISAM AUTO_INCREMENT on the second column of a key

    một bộ đếm cho cả bảng

    MyISAM đếm theo nhóm của cột đầu tiên trong khóa; PostgreSQL có một bộ đếm cho mỗi cột.

    Dòng báo cáo: myisam_group_autoincrement

  • ON UPDATE CURRENT_TIMESTAMP

    một trình kích hoạt BEFORE UPDATE

    Trình kích hoạt đặt cột thành thời điểm hiện tại khi một hàng thay đổi mà lệnh cập nhật không đặt nó, như MySQL.

    Dòng báo cáo: on_update_trigger

  • generated columns

    STORED

    PostgreSQL 13 đến 17 chỉ lưu cột tính toán; công thức giữ nguyên.

    Dòng báo cáo: virtual_as_stored

  • generated columns with functions PostgreSQL lacks

    một cột thường

    Công thức không viết được cho PostgreSQL để lại một cột thường và một dòng trong báo cáo.

    Dòng báo cáo: generated_not_translated

  • INVISIBLE columns

    cột thường

    PostgreSQL không có cột ẩn.

    Dòng báo cáo: invisible_column

  • CHECK constraints

    được chuyển đổi, viết trực tiếp trong CREATE TABLE

    Ràng buộc kiểm tra viết trực tiếp được kiểm tra khi từng hàng được nạp, thay vì quét lại cho từng ràng buộc sau đó.

  • CHECK constraints with functions PostgreSQL lacks

    không được tạo

    Ràng buộc kiểm tra không viết được cho PostgreSQL sẽ bị bỏ và được báo cáo.

    Dòng báo cáo: check_skipped

  • CHECK ... NOT ENFORCED

    không được tạo

    MySQL giữ các ràng buộc kiểm tra này nhưng không áp dụng, nên các hàng có thể vi phạm chúng.

    Dòng báo cáo: check_not_enforced

  • defaults with functions PostgreSQL lacks

    không có giá trị mặc định

    Giá trị mặc định không viết được cho PostgreSQL sẽ bị bỏ và được báo cáo.

    Dòng báo cáo: default_not_translated

  • keys and indexes on a prefix, c(20)

    chỉ mục trên left(c, 20)

    PostgreSQL lập chỉ mục trên biểu thức, nên cùng phần tiền tố được lập chỉ mục.

    Dòng báo cáo: prefix_unique

  • FULLTEXT indexes

    GIN trên to_tsvector('simple', ...)

    Tìm kiếm toàn văn dùng @@ thay cho MATCH ... AGAINST.

    Dòng báo cáo: fulltext_as_gin

  • indexes on values over 2,000 bytes

    hash

    Một mục btree không chứa được giá trị dài như vậy; chỉ mục hash vẫn tìm được các giá trị bằng nhau.

    Dòng báo cáo: index_on_wide_values

  • SPATIAL indexes

    không được tạo khi không có PostGIS

    Chỉ mục không gian cần PostGIS.

    Dòng báo cáo: spatial_index_skipped

  • functional indexes PostgreSQL can't write

    không được tạo

    Chỉ mục trên biểu thức không viết được cho PostgreSQL sẽ bị bỏ và được báo cáo.

    Dòng báo cáo: index_skipped

  • foreign keys

    sau dữ liệu, NOT VALID, rồi xác thực kèm cảnh báo về hàng mồ côi

    Bản dump nạp với FOREIGN_KEY_CHECKS=0 và MyISAM không bao giờ kiểm tra, nên hàng không có hàng cha là chuyện thường. Khóa được tạo trước và xác thực sau cùng; hàng mồ côi khiến khóa ở trạng thái NOT VALID kèm cảnh báo thay vì dừng quá trình nạp.

  • foreign keys to columns without a unique key

    không được tạo

    PostgreSQL cần khóa duy nhất trên các cột được tham chiếu; InnoDB thì không.

    Dòng báo cáo: foreign_key_skipped

  • table and column names

    chữ thường khi tên vẫn duy nhất

    Trong PostgreSQL, tên chữ thường viết được mà không cần dấu ngoặc kép.

    Dòng báo cáo: identifier_renamed

  • names over 63 bytes

    rút ngắn kèm mã băm

    Tên trong PostgreSQL tối đa 63 byte; mã băm giữ cho các tên đã rút ngắn không trùng nhau.

    Dòng báo cáo: name_shortened

  • GEOMETRY, POINT, POLYGON...

    WKB trong bytea

    Khi không có PostGIS, định dạng nhị phân chuẩn well-known binary giữ chính xác mọi dữ liệu hình học.

    Dòng báo cáo: geometry_as_wkb

  • INET4, INET6, UUID (MariaDB)

    inet, uuid

    PostgreSQL có cùng các kiểu này.

  • BINARY, VARBINARY, BLOB

    bytea

    Byte vẫn là byte.

  • PARTITION BY

    một bảng

    Các hàng giữ nguyên; hãy phân vùng lại bảng trong PostgreSQL nếu cần.

    Dòng báo cáo: partitions_dropped

  • WITH SYSTEM VERSIONING (MariaDB)

    bảng chứa các hàng hiện tại

    Bản dump chỉ chứa các hàng hiện tại.

    Dòng báo cáo: system_versioning_dropped

  • MyISAM, MEMORY and other engines

    bảng thường

    PostgreSQL có một engine bảng duy nhất.

    Dòng báo cáo: engine_dropped

  • views, triggers, procedures, functions and events

    được liệt kê trong báo cáo

    Mã của chúng viết bằng ngôn ngữ của MySQL, nên được liệt kê để bạn tạo lại.

    Dòng báo cáo: not_converted_objects

  • dumps without CREATE TABLE

    kiểu suy ra từ giá trị

    Bản dump tạo với --no-create-info chỉ có các hàng, nên kiểu được suy ra từ giá trị.

    Dòng báo cáo: no_schema

  • geometries in a dump without CREATE TABLE

    WKB trong bytea

    Định dạng hình học của MySQL được nhận diện từ giá trị và lưu dưới dạng WKB chuẩn.

    Dòng báo cáo: geometry_inferred

  • _ci collations

    so sánh chính xác

    PostgreSQL so sánh văn bản chính xác, trừ khi được chỉ định khác.

    Dòng báo cáo: case_insensitive_collation

  • SET NAMES utf8 from utf8mb4 tables

    được chuyển đổi, kèm cảnh báo

    mysqldump của MySQL 5.x mặc định ghi utf8 3 byte và thay mọi emoji bằng dấu chấm hỏi trước khi bất kỳ trình chuyển đổi nào thấy tệp.

    Dòng báo cáo: dump_lost_four_byte_chars

  • dumps without SET NAMES whose text isn't UTF-8

    đọc dưới dạng Latin-1 (Windows-1252)

    latin1 của MySQL là Windows-1252, bảng mã thường gặp của những bản dump như vậy.

    Dòng báo cáo: charset_guessed

  • sjis, cp932, gbk, big5 dumps

    đọc dưới dạng UTF-8, kèm cảnh báo

    Các bảng mã này chưa được giải mã.

    Dòng báo cáo: unsupported_charset

  • UNHEX('..'), CONVERT(b'..', UNSIGNED), CONVERT(".." USING x), ST_GeomFromText('..') in rows

    được tính ra giá trị

    Một số công cụ dump ghi giá trị dưới dạng các lệnh gọi này; chúng được đọc thành giá trị mà chúng tạo ra, với WKT địa lý được chuyển sang kinh độ trước.

  • other expressions in rows

    NULL

    Trình chuyển đổi không chạy cơ sở dữ liệu thì không tính được chúng.

    Dòng báo cáo: expression_value

  • DEFAULT in VALUES

    giá trị mặc định của cột

    Giá trị mặc định dạng hằng được sao chép vào hàng.

    Dòng báo cáo: default_keyword_filled

  • DEFAULT in VALUES without a literal default

    NULL

    Không có giá trị nào để sao chép.

    Dòng báo cáo: default_keyword_null

  • REPLACE and INSERT IGNORE

    hàng thường

    Bản dump có một hàng cho mỗi khóa, nên các hàng vẫn giống nhau.

    Dòng báo cáo: replace_as_insert

  • types IntoSQL doesn't know

    text

    Văn bản chứa được mọi giá trị; hãy đổi kiểu sau khi nạp.

    Dòng báo cáo: unknown_type

  • values that don't fit their column

    NULL

    Bản dump bị hỏng hoặc viết tay có thể chứa giá trị mà cột không chứa được; chúng trở thành NULL để phần còn lại được nạp.

    Dòng báo cáo: invalid_value_null

  • unreadable geometries

    NULL

    Byte không phải dữ liệu hình học thì không lưu được dưới dạng hình học.

    Dòng báo cáo: bad_geometry

  • CREATE SEQUENCE (MariaDB)

    CREATE SEQUENCE kèm giá trị hiện tại

    Sequence của PostgreSQL nhận cùng các tùy chọn.

Trong MySQLTrong PostgreSQLDòng báo cáo
TINYINT(1), BOOLboolean khi mọi giá trị là 0 hoặc 1, nếu không thì smallintBOOL của MySQL là TINYINT(1), chứa được mọi số từ -128 đến 127. Cột chỉ chứa 0 và 1 trở thành boolean; cột chứa 2 hoặc -1 vẫn là số để không giá trị nào đổi nghĩa.bool_kept_numeric
UNSIGNED integerskiểu số nguyên rộng hơn kế tiếp kèm CHECK không âm; BIGINT UNSIGNED là bigint khi mọi giá trị vừa, nếu không thì numeric(20,0)PostgreSQL không có số nguyên không dấu. Kiểu rộng hơn chứa được toàn bộ dải không dấu, và ràng buộc kiểm tra chặn giá trị âm như MySQL.unsigned_widened
ZEROFILL and display widthsbị bỏThêm số 0 phía trước là cách hiển thị số, không phải một phần của số. Các số được giữ; hãy định dạng khi đọc nếu cần phần số 0 đó.zerofill_dropped
FLOAT(M,D)real hoặc double precision, bỏ số chữ số thập phân cố địnhSố dấu phẩy động của PostgreSQL không có số chữ số thập phân cố định. Giá trị đã lưu được sao chép nguyên trạng.float_scale_dropped
BIT(1), BIT(n)boolean, bit(n)Một bit đơn là có hoặc không; trường bit rộng hơn giữ mọi bit.
zero, partial or impossible dates (0000-00-00, 2024-02-30)NULLPostgreSQL chỉ lưu ngày có thật trên lịch. MySQL giữ ngày bằng 0 và ngày không hợp lệ khi chế độ SQL cho phép; chúng trở thành NULL và báo cáo đếm số lượng.invalid_date_null
NOT NULL columns with values that become NULLbỏ NOT NULLCột có giá trị phải chuyển thành NULL không thể giữ NOT NULL, nếu không quá trình nạp sẽ dừng.not_null_relaxed
DEFAULT '0000-00-00'không có giá trị mặc địnhGiá trị mặc định mà PostgreSQL không lưu được sẽ bị bỏ, thay vì thay bằng một ngày bịa ra.zero_date_default
TIMEtime khi mọi giá trị nằm trong một ngày, nếu không thì intervalTIME của MySQL là khoảng thời gian từ -838:59:59 đến 838:59:59. Cột có giá trị nằm trong một ngày vẫn là giờ trong ngày; cột có giá trị dài hơn hoặc âm trở thành interval.time_as_interval
YEARsmallint kèm CHECK phạm viPostgreSQL không có kiểu năm; ràng buộc kiểm tra giữ đúng các giá trị MySQL cho phép.
CHAR(n)varchar(n)MySQL bỏ khoảng trắng cuối của giá trị CHAR khi đọc, còn char(n) của PostgreSQL sẽ thêm lại, nên varchar(n) giữ giá trị đúng như MySQL trả về.
DATETIMEtimestampDATETIME là thời gian theo đồng hồ, không kèm múi giờ, giống timestamp của PostgreSQL.
TIMESTAMPtimestamptz theo múi giờ bản dump nêu, UTC khi không nêuTIMESTAMP là một thời điểm. Bản dump nêu múi giờ đã dùng khi ghi (mysqldump ghi UTC); nếu không, giá trị được đọc theo UTC và báo cáo ghi rõ điều đó.timestamp_zone_assumed
ENUMtext kèm CHECK các giá trịVăn bản kèm ràng buộc kiểm tra giữ đúng các giá trị và dễ thay đổi hơn enum type của PostgreSQL.
ENUM holding '' (MySQL's error value)giá trị rỗng được ràng buộc kiểm tra cho phépMySQL lưu chuỗi rỗng khi một giá trị không hợp lệ được ghi vào ENUM ở chế độ SQL không nghiêm ngặt. Các hàng đó được giữ và ràng buộc kiểm tra cho phép chúng.enum_invalid_value
ENUM or SET holding values outside its listkhông có CHECKGiá trị không có trong danh sách sẽ vi phạm ràng buộc kiểm tra, nên ràng buộc không được tạo.enum_check_skipped
SETtext[] kèm CHECK rằng mọi phần tử có trong danh sáchMảng giữ từng phần tử riêng, nên truy vấn có thể kiểm tra một phần tử có thuộc tập hợp không.
JSONjsonb; json khi một giá trị chứa \u0000jsonb là kiểu PostgreSQL lập chỉ mục và truy vấn tốt, nhưng nó từ chối chuỗi thoát \u0000, nên cột có chuỗi này vẫn là json.json_not_jsonb
NUL bytes in textbị xóaVăn bản PostgreSQL không chứa được byte NUL. Byte này bị xóa và báo cáo đếm các giá trị.nul_removed
text that isn't valid in its character setbyte lỗi thành ký tự thay thếVăn bản PostgreSQL phải là UTF-8 hợp lệ.invalid_utf8_replaced
text decoded twice (ñ)sao chép nguyên trạngBản dump chứa đúng các ký tự này, nên chúng được sao chép; báo cáo chỉ ra chúng.mojibake_suspected
AUTO_INCREMENTGENERATED BY DEFAULT AS IDENTITY, bộ đếm đặt sau các id đã sao chépCột identity nhận các id đã sao chép, và bộ đếm tiếp tục sau id lớn nhất hoặc AUTO_INCREMENT của bản dump, tùy giá trị nào lớn hơn.
MyISAM AUTO_INCREMENT on the second column of a keymột bộ đếm cho cả bảngMyISAM đếm theo nhóm của cột đầu tiên trong khóa; PostgreSQL có một bộ đếm cho mỗi cột.myisam_group_autoincrement
ON UPDATE CURRENT_TIMESTAMPmột trình kích hoạt BEFORE UPDATETrình kích hoạt đặt cột thành thời điểm hiện tại khi một hàng thay đổi mà lệnh cập nhật không đặt nó, như MySQL.on_update_trigger
generated columnsSTOREDPostgreSQL 13 đến 17 chỉ lưu cột tính toán; công thức giữ nguyên.virtual_as_stored
generated columns with functions PostgreSQL lacksmột cột thườngCông thức không viết được cho PostgreSQL để lại một cột thường và một dòng trong báo cáo.generated_not_translated
INVISIBLE columnscột thườngPostgreSQL không có cột ẩn.invisible_column
CHECK constraintsđược chuyển đổi, viết trực tiếp trong CREATE TABLERàng buộc kiểm tra viết trực tiếp được kiểm tra khi từng hàng được nạp, thay vì quét lại cho từng ràng buộc sau đó.
CHECK constraints with functions PostgreSQL lackskhông được tạoRàng buộc kiểm tra không viết được cho PostgreSQL sẽ bị bỏ và được báo cáo.check_skipped
CHECK ... NOT ENFORCEDkhông được tạoMySQL giữ các ràng buộc kiểm tra này nhưng không áp dụng, nên các hàng có thể vi phạm chúng.check_not_enforced
defaults with functions PostgreSQL lackskhông có giá trị mặc địnhGiá trị mặc định không viết được cho PostgreSQL sẽ bị bỏ và được báo cáo.default_not_translated
keys and indexes on a prefix, c(20)chỉ mục trên left(c, 20)PostgreSQL lập chỉ mục trên biểu thức, nên cùng phần tiền tố được lập chỉ mục.prefix_unique
FULLTEXT indexesGIN trên to_tsvector('simple', ...)Tìm kiếm toàn văn dùng @@ thay cho MATCH ... AGAINST.fulltext_as_gin
indexes on values over 2,000 byteshashMột mục btree không chứa được giá trị dài như vậy; chỉ mục hash vẫn tìm được các giá trị bằng nhau.index_on_wide_values
SPATIAL indexeskhông được tạo khi không có PostGISChỉ mục không gian cần PostGIS.spatial_index_skipped
functional indexes PostgreSQL can't writekhông được tạoChỉ mục trên biểu thức không viết được cho PostgreSQL sẽ bị bỏ và được báo cáo.index_skipped
foreign keyssau dữ liệu, NOT VALID, rồi xác thực kèm cảnh báo về hàng mồ côiBản dump nạp với FOREIGN_KEY_CHECKS=0 và MyISAM không bao giờ kiểm tra, nên hàng không có hàng cha là chuyện thường. Khóa được tạo trước và xác thực sau cùng; hàng mồ côi khiến khóa ở trạng thái NOT VALID kèm cảnh báo thay vì dừng quá trình nạp.
foreign keys to columns without a unique keykhông được tạoPostgreSQL cần khóa duy nhất trên các cột được tham chiếu; InnoDB thì không.foreign_key_skipped
table and column nameschữ thường khi tên vẫn duy nhấtTrong PostgreSQL, tên chữ thường viết được mà không cần dấu ngoặc kép.identifier_renamed
names over 63 bytesrút ngắn kèm mã bămTên trong PostgreSQL tối đa 63 byte; mã băm giữ cho các tên đã rút ngắn không trùng nhau.name_shortened
GEOMETRY, POINT, POLYGON...WKB trong byteaKhi không có PostGIS, định dạng nhị phân chuẩn well-known binary giữ chính xác mọi dữ liệu hình học.geometry_as_wkb
INET4, INET6, UUID (MariaDB)inet, uuidPostgreSQL có cùng các kiểu này.
BINARY, VARBINARY, BLOBbyteaByte vẫn là byte.
PARTITION BYmột bảngCác hàng giữ nguyên; hãy phân vùng lại bảng trong PostgreSQL nếu cần.partitions_dropped
WITH SYSTEM VERSIONING (MariaDB)bảng chứa các hàng hiện tạiBản dump chỉ chứa các hàng hiện tại.system_versioning_dropped
MyISAM, MEMORY and other enginesbảng thườngPostgreSQL có một engine bảng duy nhất.engine_dropped
views, triggers, procedures, functions and eventsđược liệt kê trong báo cáoMã của chúng viết bằng ngôn ngữ của MySQL, nên được liệt kê để bạn tạo lại.not_converted_objects
dumps without CREATE TABLEkiểu suy ra từ giá trịBản dump tạo với --no-create-info chỉ có các hàng, nên kiểu được suy ra từ giá trị.no_schema
geometries in a dump without CREATE TABLEWKB trong byteaĐịnh dạng hình học của MySQL được nhận diện từ giá trị và lưu dưới dạng WKB chuẩn.geometry_inferred
_ci collationsso sánh chính xácPostgreSQL so sánh văn bản chính xác, trừ khi được chỉ định khác.case_insensitive_collation
SET NAMES utf8 from utf8mb4 tablesđược chuyển đổi, kèm cảnh báomysqldump của MySQL 5.x mặc định ghi utf8 3 byte và thay mọi emoji bằng dấu chấm hỏi trước khi bất kỳ trình chuyển đổi nào thấy tệp.dump_lost_four_byte_chars
dumps without SET NAMES whose text isn't UTF-8đọc dưới dạng Latin-1 (Windows-1252)latin1 của MySQL là Windows-1252, bảng mã thường gặp của những bản dump như vậy.charset_guessed
sjis, cp932, gbk, big5 dumpsđọc dưới dạng UTF-8, kèm cảnh báoCác bảng mã này chưa được giải mã.unsupported_charset
UNHEX('..'), CONVERT(b'..', UNSIGNED), CONVERT(".." USING x), ST_GeomFromText('..') in rowsđược tính ra giá trịMột số công cụ dump ghi giá trị dưới dạng các lệnh gọi này; chúng được đọc thành giá trị mà chúng tạo ra, với WKT địa lý được chuyển sang kinh độ trước.
other expressions in rowsNULLTrình chuyển đổi không chạy cơ sở dữ liệu thì không tính được chúng.expression_value
DEFAULT in VALUESgiá trị mặc định của cộtGiá trị mặc định dạng hằng được sao chép vào hàng.default_keyword_filled
DEFAULT in VALUES without a literal defaultNULLKhông có giá trị nào để sao chép.default_keyword_null
REPLACE and INSERT IGNOREhàng thườngBản dump có một hàng cho mỗi khóa, nên các hàng vẫn giống nhau.replace_as_insert
types IntoSQL doesn't knowtextVăn bản chứa được mọi giá trị; hãy đổi kiểu sau khi nạp.unknown_type
values that don't fit their columnNULLBản dump bị hỏng hoặc viết tay có thể chứa giá trị mà cột không chứa được; chúng trở thành NULL để phần còn lại được nạp.invalid_value_null
unreadable geometriesNULLByte không phải dữ liệu hình học thì không lưu được dưới dạng hình học.bad_geometry
CREATE SEQUENCE (MariaDB)CREATE SEQUENCE kèm giá trị hiện tạiSequence của PostgreSQL nhận cùng các tùy chọn.

Nạp tập lệnh vào PostgreSQL

Tập lệnh tạo bảng, sao chép các hàng, rồi thêm khóa, chỉ mục và khóa ngoại, nên nạp nhanh và dừng ở lỗi đầu tiên.

psql -v ON_ERROR_STOP=1 -d mydb -f mysql.postgresql.sql

Khóa ngoại được thêm dưới dạng NOT VALID rồi được xác thực. Nếu một hàng trỏ tới hàng không tồn tại, tập lệnh cho bạn biết ràng buộc nào, thay vì thất bại giữa chừng.

Với bản dump lớn, hãy tạo cơ sở dữ liệu trước và chạy tập lệnh bằng psql trên cùng máy với máy chủ.

Tạo bản dump MySQL để có kết quả tốt nhất

Trình chuyển đổi đọc những gì bản dump chứa. Các tùy chọn sau giữ lại nhiều dữ liệu hơn trong đó:

  • --default-character-set=utf8mb4 giữ emoji và các ký tự 4 byte khác, những ký tự mà bản dump utf8 làm mất trước khi trình chuyển đổi thấy.
  • --hex-blob ghi cột nhị phân dưới dạng thập lục phân, không bị hỏng khi sao chép giữa các hệ thống.
  • --routines --triggers --events thêm các đối tượng đó vào bản dump, để báo cáo có thể liệt kê chúng.

Những gì không được chuyển đổi

Khung nhìn, trình kích hoạt, thủ tục lưu trữ, hàm và sự kiện được viết bằng ngôn ngữ riêng của từng cơ sở dữ liệu. Chúng được liệt kê theo tên trong báo cáo, không bao giờ bị bỏ âm thầm, để bạn viết lại cho PostgreSQL.

Đo đối chiếu với pgloader

Cùng các bản dump, được IntoSQL và pgloader 3.6.7 chuyển đổi và nạp trên cùng một máy (i9-10900K 10 nhân với SATA SSD), vào tháng 10 năm 2026.

  • Cột TINYINT(1) chứa 2, -1 và -5: pgloader nạp true cho từng giá trị, không có cảnh báo. IntoSQL giữ các số và báo cáo giải thích lý do.
  • Bản dump có giá trị mặc định 'it's', bảng có tên chứa dấu backtick, ENUM chứa giá trị rỗng và TIME trên 24 giờ: pgloader dừng lại. IntoSQL chuyển đổi và nạp được.
  • Dữ liệu pgloader nạp đã mất khóa chính, khóa duy nhất, khóa ngoại và identity. IntoSQL giữ tất cả.
  • Bản dump 5.3 GB với 30 triệu hàng: pgloader cần khôi phục nó vào một MySQL đang chạy trước, mất 18 phút, rồi hết bộ nhớ với cấu hình mặc định. IntoSQL chuyển đổi bản dump trong 10 giây, và psql nạp tập lệnh trong khoảng 3 phút.
  • Trên 476 bản dump từ MySQL 5.5 đến 9 và MariaDB 10.3 đến 12, nạp vào PostgreSQL 13 và 18: không có lỗi nạp, và không giá trị nào thay đổi mà không có dòng trong báo cáo.

Câu hỏi về MySQL sang PostgreSQL

Chưa có câu trả lời ở đây? Hãy viết cho chúng tôi từ trang liên hệ, sẽ có người trả lời. Trang liên hệ

Bản dump của tôi có bị tải lên không?

Không. Trình chuyển đổi chạy trong trình duyệt và đọc bản dump từ ổ đĩa theo từng phần, nên nó không bao giờ rời khỏi máy tính của bạn. Ứng dụng máy tính và dòng lệnh cũng chuyển đổi ngay trên máy tính của bạn.

Bản dump có thể lớn đến đâu?

Trình chuyển đổi không bao giờ giữ toàn bộ bản dump trong bộ nhớ: nó đọc tệp hai lần, theo từng đoạn, và ghi tập lệnh trong lúc đọc. Bản dump nhiều gigabyte vẫn chuyển đổi được trong trình duyệt, trong ứng dụng máy tính và bằng dòng lệnh.

Nó có đọc được bản dump MariaDB không?

Có. Bản dump từ mariadb-dump và từ MariaDB 10.3 đến 12 được chuyển đổi theo cùng cách, kể cả các cột INET6, INET4 và UUID của MariaDB.

Ngày 0000-00-00 sẽ ra sao?

PostgreSQL không có ngày bằng 0, nên chúng trở thành NULL và cột chấp nhận NULL. Báo cáo cho biết số lượng trong mỗi cột.

Giá trị AUTO_INCREMENT có được giữ không?

Có. Mỗi cột AUTO_INCREMENT trở thành cột identity, mọi hàng giữ id của nó, và id tiếp theo tiếp tục sau id lớn nhất, hoặc sau AUTO_INCREMENT của bảng nếu giá trị đó lớn hơn.

TINYINT(1) có thành boolean không?

Chỉ khi mọi giá trị trong cột là 0 hoặc 1. Nếu cột chứa số khác, như 2 hoặc -1, nó vẫn là số và báo cáo giải thích lý do, nên không giá trị nào vô tình thành true.

Còn thủ tục lưu trữ và trình kích hoạt thì sao?

Chúng được liệt kê theo tên trong báo cáo và không được chuyển đổi, vì mỗi cơ sở dữ liệu viết chúng bằng ngôn ngữ riêng. ON UPDATE CURRENT_TIMESTAMP là ngoại lệ: nó trở thành một trình kích hoạt PostgreSQL.

Tập lệnh nạp được trên những phiên bản PostgreSQL nào?

PostgreSQL 13 đến 18. Cùng một tập lệnh nạp được trên từng phiên bản, và dừng ở lỗi đầu tiên nếu có sự cố.