MySQL to DB2 Converter: Syntax Guide & Examples
A complete reference for converting MySQL queries and schemas to DB2 LUW. Covers every major syntax difference with side-by-side examples.
Why Convert MySQL to DB2?
IBM DB2 is an enterprise-grade relational database widely used in banking, insurance, government, and large-scale transactional systems. If your organization is standardizing on DB2 LUW (Linux, UNIX, and Windows) or you need to integrate with mainframe systems, migrating your MySQL queries and schemas to DB2 is a necessary step.
DB2 offers advanced features like temporal tables, multi-temperature storage, workload management, and deep integration with IBM's data platform ecosystem. It also provides robust support for the SQL standard, making it well-suited for regulated industries where compliance and auditability are critical.
While both MySQL and DB2 follow the SQL standard, they differ significantly in auto-increment handling, pagination syntax, identifier quoting, built-in functions, and data types. This guide covers every difference you will encounter during migration.
Key Syntax Differences
| Feature | MySQL | DB2 |
|---|---|---|
| Auto-increment | AUTO_INCREMENT |
GENERATED ALWAYS AS IDENTITY |
| Identifier quoting | `backticks` |
"double quotes" or unquoted |
| NULL handling | IFNULL(a, b) |
COALESCE(a, b) |
| Row limiting | LIMIT n |
FETCH FIRST n ROWS ONLY |
| Current timestamp | NOW() |
CURRENT_TIMESTAMP |
| Group concatenation | GROUP_CONCAT(col) |
LISTAGG(col, ',') |
| Boolean type | TINYINT(1) |
SMALLINT with CHECK constraint |
| ENUM type | Inline ENUM('a','b') |
VARCHAR with CHECK constraint |
| UNSIGNED integer | INT UNSIGNED |
INTEGER with CHECK (col >= 0) |
| Date arithmetic | DATE_ADD(d, INTERVAL n DAY) |
d + n DAYS or TIMESTAMPADD |
| Storage engine | ENGINE=InnoDB |
Not applicable (remove) |
Common Conversions with Examples
AUTO_INCREMENT to GENERATED ALWAYS AS IDENTITY
MySQL uses AUTO_INCREMENT as a column attribute. DB2 uses the SQL-standard GENERATED ALWAYS AS IDENTITY clause, which creates an implicit sequence for the column.
-- MySQL
CREATE TABLE users (
id INT AUTO_INCREMENT PRIMARY KEY,
name VARCHAR(100) NOT NULL
) ENGINE=InnoDB;
-- DB2
CREATE TABLE users (
id INTEGER GENERATED ALWAYS AS IDENTITY PRIMARY KEY,
name VARCHAR(100) NOT NULL
);
If you need to allow manual inserts for the identity column, use GENERATED BY DEFAULT AS IDENTITY instead. You can also control the starting value and increment:
-- DB2 with explicit sequence options
CREATE TABLE users (
id INTEGER GENERATED ALWAYS AS IDENTITY
(START WITH 1, INCREMENT BY 1) PRIMARY KEY,
name VARCHAR(100) NOT NULL
);
Identifier Quoting
MySQL uses backticks to quote identifiers. DB2 uses standard double quotes, or you can simply remove the quoting if the identifiers are not reserved words.
-- MySQL
SELECT `order`, `group`, `select` FROM `user_data`;
-- DB2
SELECT "ORDER", "GROUP", "SELECT" FROM user_data;
Note that DB2 identifiers are case-insensitive when unquoted (they fold to uppercase). When quoted with double quotes, they become case-sensitive.
LIMIT to FETCH FIRST n ROWS ONLY
DB2 does not support the LIMIT clause. Instead, use the SQL-standard FETCH FIRST n ROWS ONLY syntax. For pagination with an offset, combine it with OFFSET.
-- MySQL
SELECT * FROM products LIMIT 10;
SELECT * FROM products LIMIT 10 OFFSET 20;
-- DB2
SELECT * FROM products FETCH FIRST 10 ROWS ONLY;
SELECT * FROM products OFFSET 20 ROWS FETCH FIRST 10 ROWS ONLY;
In older DB2 versions that do not support OFFSET, use ROW_NUMBER() in a subquery:
-- DB2 (older versions)
SELECT * FROM (
SELECT t.*, ROW_NUMBER() OVER (ORDER BY id) AS rn
FROM products t
) WHERE rn BETWEEN 21 AND 30;
IFNULL to COALESCE
MySQL's IFNULL() takes exactly two arguments. DB2 uses the SQL-standard COALESCE() function, which accepts any number of arguments and returns the first non-NULL value.
-- MySQL
SELECT IFNULL(nickname, name) AS display_name FROM users;
-- DB2
SELECT COALESCE(nickname, name) AS display_name FROM users;
COALESCE is also valid in MySQL, so using it everywhere makes your queries more portable. See our guide on SQL fundamentals for more on NULL handling.
NOW() to CURRENT_TIMESTAMP
MySQL's NOW() function is not available in DB2. Use the SQL-standard CURRENT_TIMESTAMP special register instead.
-- MySQL
INSERT INTO logs (message, created_at) VALUES ('login', NOW());
-- DB2
INSERT INTO logs (message, created_at) VALUES ('login', CURRENT_TIMESTAMP);
DB2 also provides CURRENT_DATE and CURRENT_TIME for date-only and time-only values.
GROUP_CONCAT to LISTAGG
MySQL's GROUP_CONCAT() concatenates values from multiple rows into a single string. DB2 uses LISTAGG() to achieve the same result.
-- MySQL
SELECT department, GROUP_CONCAT(name ORDER BY name SEPARATOR ', ')
FROM employees GROUP BY department;
-- DB2
SELECT department, LISTAGG(name, ', ') WITHIN GROUP (ORDER BY name)
FROM employees GROUP BY department;
Date Function Differences
MySQL uses DATE_ADD and DATE_SUB for date arithmetic. DB2 uses labeled durations or the TIMESTAMPADD function.
-- MySQL
SELECT DATE_ADD(created_at, INTERVAL 30 DAY) FROM orders;
SELECT DATE_SUB(created_at, INTERVAL 7 DAY) FROM orders;
SELECT DATEDIFF(end_date, start_date) FROM projects;
-- DB2
SELECT created_at + 30 DAYS FROM orders;
SELECT created_at - 7 DAYS FROM orders;
SELECT DAYS(end_date) - DAYS(start_date) FROM projects;
For extracting parts of a date, MySQL uses dedicated functions while DB2 uses EXTRACT or dedicated functions:
-- MySQL
SELECT YEAR(created_at), MONTH(created_at) FROM orders;
-- DB2
SELECT EXTRACT(YEAR FROM created_at), EXTRACT(MONTH FROM created_at) FROM orders;
-- or
SELECT YEAR(created_at), MONTH(created_at) FROM orders;
ENUM to CHECK Constraint
DB2 does not have an ENUM data type. Use a VARCHAR column with a CHECK constraint to restrict allowed values.
-- MySQL
CREATE TABLE orders (
id INT AUTO_INCREMENT PRIMARY KEY,
status ENUM('pending', 'shipped', 'delivered') DEFAULT 'pending'
) ENGINE=InnoDB;
-- DB2
CREATE TABLE orders (
id INTEGER GENERATED ALWAYS AS IDENTITY PRIMARY KEY,
status VARCHAR(20) DEFAULT 'pending'
CHECK (status IN ('pending', 'shipped', 'delivered'))
);
UNSIGNED to CHECK Constraint
DB2 does not support the UNSIGNED attribute. Use a CHECK constraint to enforce non-negative values.
-- MySQL
CREATE TABLE products (
id INT UNSIGNED AUTO_INCREMENT PRIMARY KEY,
price DECIMAL(10,2) UNSIGNED NOT NULL
) ENGINE=InnoDB;
-- DB2
CREATE TABLE products (
id INTEGER GENERATED ALWAYS AS IDENTITY PRIMARY KEY CHECK (id >= 0),
price DECIMAL(10,2) NOT NULL CHECK (price >= 0)
);
Data Type Mapping
| MySQL Type | DB2 Type | Notes |
|---|---|---|
TINYINT | SMALLINT | No TINYINT in DB2 |
TINYINT(1) | SMALLINT | DB2 has no native BOOLEAN; use SMALLINT with CHECK (col IN (0, 1)) |
INT | INTEGER | Same 4-byte range |
INT UNSIGNED | INTEGER | Add CHECK (col >= 0) |
BIGINT | BIGINT | Same |
FLOAT | REAL | 4-byte floating point |
DOUBLE | DOUBLE | 8-byte floating point |
DECIMAL(p,s) | DECIMAL(p,s) | Same |
DATETIME | TIMESTAMP | DB2 TIMESTAMP has microsecond precision |
DATE | DATE | Same |
TIME | TIME | Same |
TEXT | CLOB | Character large object |
MEDIUMTEXT / LONGTEXT | CLOB | Specify size: CLOB(1M), CLOB(2G) |
BLOB | BLOB | Same; specify size if needed |
VARCHAR(255) | VARCHAR(255) | Same; DB2 max is 32672 bytes |
ENUM('a','b') | VARCHAR + CHECK | No ENUM type in DB2 |
SET('a','b') | VARCHAR + application logic | No SET type in DB2 |
JSON | CLOB or BSON | DB2 11.1+ has JSON functions with SYSTOOLS schema |
CHAR(n) | CHAR(n) | Same; DB2 max is 254 bytes |
Step-by-Step Migration Guide
- Export your MySQL schema. Run
mysqldump --no-data your_database > schema.sqlto get the DDL statements without data. - Convert the schema. Replace
AUTO_INCREMENTwithGENERATED ALWAYS AS IDENTITY, remove backticks or replace with double quotes, changeTINYINT(1)toSMALLINT, replaceTEXTwithCLOB, replaceENUMwithVARCHAR + CHECK, removeENGINE=InnoDBclauses, and addCHECKconstraints forUNSIGNEDcolumns. - Export the data. Export as CSV or use a delimited format. DB2's
LOADutility orIMPORTcommand can ingest CSV files efficiently. For large datasets, theLOADutility is significantly faster thanIMPORT. - Update your queries. Replace
LIMITwithFETCH FIRST n ROWS ONLY,IFNULLwithCOALESCE,GROUP_CONCATwithLISTAGG,NOW()withCURRENT_TIMESTAMP, andDATE_ADD/DATE_SUBwith DB2 labeled duration syntax. - Test with a staging database. Load the converted schema and data into a test DB2 instance. Run your application test suite to catch remaining incompatibilities, paying special attention to quoting and case sensitivity.
- Switch production. Once tests pass, update your connection strings and JDBC drivers. DB2 uses the
db2jcc4.jarJDBC driver. Keep the MySQL instance available during the transition period for rollback.
For more on SQL fundamentals, see our What is SQL guide. If you are working with joins during migration, check our SQL Joins Explained tutorial.
Convert Automatically with AI2SQL
Instead of manually translating every query, you can paste your MySQL query into the SQL Converter tool and get correct DB2 syntax automatically, whether you need a simple SELECT or a complex multi-table join with window functions.
This is especially useful during migration, when you have hundreds of queries to convert and cannot afford to miss a subtle syntax difference like LIMIT vs FETCH FIRST or IFNULL vs COALESCE. Try the converter free and generate your first DB2 query in seconds.
Looking for other conversions? See our MySQL to PostgreSQL converter. You can also explore all available SQL converter tools.
Frequently Asked Questions
Can I convert MySQL queries to DB2 automatically?
Yes. Tools like AI2SQL let you describe what you need in plain English and generate the correct DB2 syntax automatically. For manual conversion, the main changes are replacing AUTO_INCREMENT with GENERATED ALWAYS AS IDENTITY, LIMIT with FETCH FIRST n ROWS ONLY, removing backticks, and swapping MySQL-specific functions like IFNULL and GROUP_CONCAT with DB2 equivalents like COALESCE and LISTAGG.
What is the DB2 equivalent of MySQL AUTO_INCREMENT?
DB2 uses GENERATED ALWAYS AS IDENTITY to auto-generate sequential values, which follows the SQL standard. You can control the starting value and increment with START WITH and INCREMENT BY clauses. Unlike MySQL's AUTO_INCREMENT, DB2 IDENTITY columns do not allow manual inserts by default unless you use GENERATED BY DEFAULT AS IDENTITY instead.
How do I handle MySQL LIMIT in DB2?
DB2 does not support the LIMIT clause. Instead, use FETCH FIRST n ROWS ONLY. For pagination with an offset, use the OFFSET clause: SELECT * FROM table OFFSET 20 ROWS FETCH FIRST 10 ROWS ONLY. In older DB2 versions, you can use ROW_NUMBER() in a subquery to achieve the same result.