MySQL ALTER Command
Overview
The ALTER TABLE statement is used to modify the structure of an existing table. You can add, delete, or modify columns, indexes, and constraints after a table has been created.
Common ALTER Operations
- Add Columns: Add new columns to tables
- Drop Columns: Remove columns from tables
- Modify Columns: Change column definitions
- Rename Columns: Change column names
- Add Constraints: Add PRIMARY KEY, FOREIGN KEY, etc.
- Drop Constraints: Remove constraints
- Change Options: Modify table options
ALTER TABLE Syntax
Basic Syntax
sql
ALTER TABLE table_name
[alter_specification [, alter_specification] ...]
alter_specification:
ADD [COLUMN] column_definition
| ADD [COLUMN] (column_definition, ...)
| DROP [COLUMN] column_name
| CHANGE [COLUMN] old_name new_name definition
| MODIFY [COLUMN] column_definition
| RENAME [TO] new_table_nameAdding Columns
Add Single Column
sql
-- Add column at end
ALTER TABLE users ADD COLUMN phone VARCHAR(20);
-- Add column with default value
ALTER TABLE users
ADD COLUMN status VARCHAR(20) DEFAULT 'active';
-- Add column with NOT NULL
ALTER TABLE users
ADD COLUMN email_verified BOOLEAN DEFAULT FALSE;
-- Add column with auto increment
ALTER TABLE users
ADD COLUMN account_number INT AUTO_INCREMENT PRIMARY KEY;Add Multiple Columns
sql
-- Add several columns
ALTER TABLE users
ADD COLUMN first_name VARCHAR(50),
ADD COLUMN last_name VARCHAR(50),
ADD COLUMN middle_name VARCHAR(50);
-- Add columns with specific options
ALTER TABLE orders
ADD COLUMN tracking_number VARCHAR(50),
ADD COLUMN shipping_date DATE,
ADD COLUMN delivery_date DATE NULL;Add Column with Position
sql
-- Add as first column
ALTER TABLE users ADD COLUMN id INT FIRST;
-- Add after specific column
ALTER TABLE users
ADD COLUMN middle_name VARCHAR(50) AFTER first_name;
-- Add at end (default)
ALTER TABLE users ADD COLUMN notes TEXT;Add Column with Constraint
sql
-- Add with PRIMARY KEY
ALTER TABLE products ADD COLUMN id INT PRIMARY KEY AUTO_INCREMENT;
-- Add with UNIQUE constraint
ALTER TABLE users
ADD COLUMN email VARCHAR(255) UNIQUE;
-- Add with FOREIGN KEY
ALTER TABLE orders
ADD COLUMN user_id INT,
ADD FOREIGN KEY (user_id) REFERENCES users(id);
-- Add with CHECK constraint (MySQL 8.0+)
ALTER TABLE employees
ADD COLUMN age INT CHECK (age >= 18 AND age <= 65);Dropping Columns
Drop Single Column
sql
-- Drop column
ALTER TABLE users DROP COLUMN phone;
-- Drop if exists (MySQL 8.0+)
ALTER TABLE users DROP COLUMN IF EXISTS phone;Drop Multiple Columns
sql
-- Drop several columns
ALTER TABLE users
DROP COLUMN fax,
DROP COLUMN pager,
DROP COLUMN work_phone;Drop and Add Column
sql
-- Drop and re-add column
ALTER TABLE users
DROP COLUMN old_column,
ADD COLUMN new_column VARCHAR(100);Modifying Columns
CHANGE vs MODIFY
sql
-- MODIFY: Change definition only
ALTER TABLE users
MODIFY COLUMN name VARCHAR(100) NOT NULL;
-- CHANGE: Change name and definition
ALTER TABLE users
CHANGE COLUMN username user_name VARCHAR(100) NOT NULL;Change Data Type
sql
-- Change VARCHAR length
ALTER TABLE users
MODIFY COLUMN email VARCHAR(255);
-- Change INT to BIGINT
ALTER TABLE orders
MODIFY COLUMN total BIGINT;
-- Change TEXT to LONGTEXT
ALTER TABLE articles
MODIFY COLUMN content LONGTEXT;
-- Change to NOT NULL
ALTER TABLE users
MODIFY COLUMN username VARCHAR(50) NOT NULL;Change Default Value
sql
-- Add default value
ALTER TABLE users
MODIFY COLUMN status VARCHAR(20) DEFAULT 'pending';
-- Change default value
ALTER TABLE users
MODIFY COLUMN created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP;
-- Remove default value
ALTER TABLE users
MODIFY COLUMN status VARCHAR(20) DEFAULT NULL;Add AUTO_INCREMENT
sql
-- Add AUTO_INCREMENT to existing column
ALTER TABLE users
MODIFY COLUMN id INT AUTO_INCREMENT;
-- Set starting value
ALTER TABLE users AUTO_INCREMENT = 1000;Renaming Columns
sql
-- Rename single column
ALTER TABLE users
CHANGE COLUMN username user_name VARCHAR(50);
-- Rename and change type
ALTER TABLE users
CHANGE COLUMN dob birth_date DATE;
-- Rename with constraint
ALTER TABLE products
CHANGE COLUMN product_id id INT PRIMARY KEY;Renaming Table
sql
-- Rename table
ALTER TABLE old_table_name RENAME TO new_table_name;
-- Alternative syntax
RENAME TABLE old_table_name TO new_table_name;
-- Rename multiple tables
RENAME TABLE
table1 TO new_table1,
table2 TO new_table2,
table3 TO new_table3;Altering Constraints
Adding Primary Key
sql
-- Add single column primary key
ALTER TABLE users ADD PRIMARY KEY (id);
-- Add composite primary key
ALTER TABLE order_items
ADD PRIMARY KEY (order_id, product_id);
-- Add primary key with auto increment
ALTER TABLE products
MODIFY COLUMN id INT AUTO_INCREMENT,
ADD PRIMARY KEY (id);Dropping Primary Key
sql
-- Drop primary key
ALTER TABLE users DROP PRIMARY KEY;
-- Drop and add new primary key
ALTER TABLE users
DROP PRIMARY KEY,
ADD PRIMARY KEY (new_id);Adding Foreign Key
sql
-- Add foreign key
ALTER TABLE orders
ADD CONSTRAINT fk_orders_user
FOREIGN KEY (user_id) REFERENCES users(id);
-- Add with ON DELETE
ALTER TABLE orders
ADD CONSTRAINT fk_orders_user
FOREIGN KEY (user_id) REFERENCES users(id)
ON DELETE CASCADE;
-- Add with ON UPDATE
ALTER TABLE order_items
ADD CONSTRAINT fk_items_product
FOREIGN KEY (product_id) REFERENCES products(id)
ON UPDATE CASCADE;Dropping Foreign Key
sql
-- Drop specific foreign key
ALTER TABLE orders DROP FOREIGN KEY fk_orders_user;
-- Find foreign key names
SHOW CREATE TABLE orders;
-- Drop foreign key by name
ALTER TABLE orders DROP FOREIGN KEY orders_ibfk_1;Adding UNIQUE Constraint
sql
-- Add single column unique
ALTER TABLE users ADD UNIQUE (email);
-- Add composite unique
ALTER TABLE user_emails
ADD UNIQUE (user_id, email_type);
-- Add named unique constraint
ALTER TABLE products
ADD CONSTRAINT uc_product_code UNIQUE (code);Dropping UNIQUE Constraint
sql
-- Drop unique index
ALTER TABLE users DROP INDEX email;
-- Drop named unique constraint
ALTER TABLE products DROP INDEX uc_product_code;Altering Indexes
Adding Indexes
sql
-- Add simple index
ALTER TABLE users ADD INDEX idx_users_email (email);
-- Add composite index
ALTER TABLE orders ADD INDEX idx_orders_user_date (user_id, order_date);
-- Add FULLTEXT index
ALTER TABLE articles ADD FULLTEXT INDEX ft_content (title, content);
-- Add spatial index
ALTER TABLE locations ADD SPATIAL INDEX sp_position (position);Dropping Indexes
sql
-- Drop index
ALTER TABLE users DROP INDEX idx_users_email;
-- Drop primary key (also removes index)
ALTER TABLE users DROP PRIMARY KEY;Altering Table Options
Change Engine
sql
-- Change storage engine
ALTER TABLE users ENGINE = InnoDB;
ALTER TABLE logs ENGINE = MyISAM;
-- Convert multiple tables
ALTER TABLE users ENGINE = InnoDB;
ALTER TABLE orders ENGINE = InnoDB;
ALTER TABLE products ENGINE = InnoDB;Change Character Set
sql
-- Change character set
ALTER TABLE users CHARACTER SET utf8mb4;
-- Change collation
ALTER TABLE users COLLATE utf8mb4_unicode_ci;
-- Change both
ALTER TABLE users
CHARACTER SET utf8mb4
COLLATE utf8mb4_unicode_ci;Change Auto Increment
sql
-- Set next auto increment value
ALTER TABLE users AUTO_INCREMENT = 10000;
-- Reset auto increment
ALTER TABLE users AUTO_INCREMENT = 1;Add Table Comment
sql
-- Add or modify table comment
ALTER TABLE users COMMENT = 'User accounts table';
-- Add column comment
ALTER TABLE users
MODIFY COLUMN name VARCHAR(100) COMMENT 'User full name';Complex ALTER Operations
Reorder Columns
sql
-- MySQL doesn't have direct REORDER
-- Must use multiple MODIFY statements
ALTER TABLE users
MODIFY COLUMN id INT FIRST,
MODIFY COLUMN name VARCHAR(100) AFTER id,
MODIFY COLUMN email VARCHAR(255) AFTER name;Convert to Different Format
sql
-- Convert to compressed row format
ALTER TABLE users ROW_FORMAT = COMPRESSED;
-- Convert to dynamic row format
ALTER TABLE users ROW_FORMAT = DYNAMIC;
-- Convert to fixed row format
ALTER TABLE users ROW_FORMAT = FIXED;Performance Considerations
ALTER Table Performance
sql
-- ALTER TABLE can be slow on large tables
-- Consider these strategies:
-- 1. Use pt-online-schema-change (external tool)
-- Allows online schema changes
-- 2. Create new table and copy data
CREATE TABLE users_new LIKE users;
-- Add/modify columns
ALTER TABLE users_new ADD COLUMN phone VARCHAR(20);
-- Copy data
INSERT INTO users_new SELECT * FROM users;
-- Swap tables
RENAME TABLE users TO users_old, users_new TO users;
-- Drop old
DROP TABLE users_old;
-- 3. Use ALGORITHM clause (MySQL 5.6+)
ALTER TABLE users
ADD COLUMN phone VARCHAR(20),
ALGORITHM = INPLACE; -- Faster, online operation
-- 4. Use LOCK clause
ALTER TABLE users
ADD COLUMN phone VARCHAR(20),
ALGORITHM = INPLACE,
LOCK = NONE; -- No locking, but longer timeALGORITHM Option
sql
-- ALGORITHM = COPY (default for some changes)
-- Creates copy of table, slow, locks table
ALTER TABLE users
ADD COLUMN phone VARCHAR(20),
ALGORITHM = COPY;
-- ALGORITHM = INPLACE (faster, minimal locking)
-- Modifies table in place
ALTER TABLE users
MODIFY COLUMN name VARCHAR(200),
ALGORITHM = INPLACE;
-- ALGORITHM = INSTANT (MySQL 8.0+, fastest)
-- No table copy, no locking
ALTER TABLE users
ADD COLUMN phone VARCHAR(20),
ALGORITHM = INSTANT;LOCK Option
sql
-- LOCK = DEFAULT (MySQL decides)
-- LOCK = NONE (allows concurrent DML)
-- LOCK = SHARED (allows concurrent reads)
-- LOCK = EXCLUSIVE (blocks all DML/DDL)
ALTER TABLE users
ADD COLUMN phone VARCHAR(20),
ALGORITHM = INPLACE,
LOCK = NONE;Practical Examples
Migration: Add User Status
sql
-- Add status column with default
ALTER TABLE users
ADD COLUMN status ENUM('active', 'inactive', 'suspended') DEFAULT 'inactive';
-- Update existing users
UPDATE users SET status = 'active' WHERE created_at < DATE_SUB(NOW(), INTERVAL 30 DAY);
-- Add index for status
ALTER TABLE users ADD INDEX idx_users_status (status);Migration: Add Soft Delete
sql
-- Add deleted_at column
ALTER TABLE users
ADD COLUMN deleted_at TIMESTAMP NULL,
ADD INDEX idx_users_deleted (deleted_at);
-- Update application logic to use soft deletes
-- Instead of: DELETE FROM users WHERE id = 1;
-- Use: UPDATE users SET deleted_at = NOW() WHERE id = 1;Migration: Add Audit Columns
sql
-- Add audit columns
ALTER TABLE orders
ADD COLUMN created_by INT NULL,
ADD COLUMN updated_by INT NULL,
ADD COLUMN created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
ADD COLUMN updated_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP;
-- Add foreign keys for audit
ALTER TABLE orders
ADD CONSTRAINT fk_orders_created
FOREIGN KEY (created_by) REFERENCES users(id),
ADD CONSTRAINT fk_orders_updated
FOREIGN KEY (updated_by) REFERENCES users(id);Migration: Normalize Data
sql
-- Create normalized table
CREATE TABLE user_phones (
id INT PRIMARY KEY AUTO_INCREMENT,
user_id INT NOT NULL,
phone VARCHAR(20) NOT NULL,
is_primary BOOLEAN DEFAULT FALSE,
FOREIGN KEY (user_id) REFERENCES users(id)
);
-- Migrate data
INSERT INTO user_phones (user_id, phone, is_primary)
SELECT id, phone, TRUE FROM users WHERE phone IS NOT NULL;
-- Add phone column (optional)
ALTER TABLE users ADD COLUMN primary_phone_id INT NULL;
UPDATE users u
SET primary_phone_id = (SELECT id FROM user_phones WHERE user_id = u.id AND is_primary = TRUE LIMIT 1);
-- Drop old column
ALTER TABLE users DROP COLUMN phone;Troubleshooting
Common Errors
sql
-- Error: Duplicate column name
-- ALTER TABLE users ADD COLUMN name VARCHAR(100);
-- Solution: Column already exists
-- Error: Key column doesn't exist
-- ALTER TABLE users ADD PRIMARY KEY (nonexistent);
-- Solution: Check column name
-- Error: Foreign key constraint fails
-- ALTER TABLE orders ADD FOREIGN KEY (user_id) REFERENCES users(id);
-- Solution: Ensure referenced column exists and has matching type
-- Error: Cannot delete column referenced by foreign key
-- ALTER TABLE users DROP COLUMN id;
-- Solution: Drop foreign key first
ALTER TABLE orders DROP FOREIGN KEY fk_orders_user;Checking Table Structure
sql
-- Show table structure
DESCRIBE table_name;
DESC table_name;
-- Show create statement
SHOW CREATE TABLE table_name;
-- Show table information
SHOW TABLE STATUS LIKE 'table_name';
-- Check columns
SELECT * FROM information_schema.COLUMNS
WHERE TABLE_NAME = 'table_name';Summary
ALTER TABLE allows you to:
ALTER TABLE:
- Modify Structure: Add, drop, change columns
- Manage Constraints: Add and drop keys
- Change Options: Engine, character set, auto-increment
- Online DDL: Use ALGORITHM and LOCK options
Consider performance impact when modifying large tables and use appropriate ALGORITHM and LOCK options.
Previous: Transactions
Next: Indexes