SQL Fundamentals
INSERT INTO Statement
The INSERT INTO statement adds new rows of data to a table. It's how you populate your database with the information your applications need.
- Single Row β Add one record at a time
- Multiple Rows β Insert many records in a single statement for efficiency
- INSERT...SELECT β Copy data from one table to another
Always specify column names β it makes your code clearer and more resilient to schema changes.
Basic Syntax
DfINSERT INTO
A DML (Data Manipulation Language) statement that adds one or more rows to a table. You specify the target table, the columns to populate, and the values to insert.
INSERT INTO table_name (column1, column2, column3)
VALUES (value1, value2, value3);
| Component | Description | Example |
|---|---|---|
table_name | Target table | customers |
column1, column2 | Columns to insert into | first_name, email |
VALUES | Keyword | Required |
value1, value2 | Values to insert | 'Alice', 'alice@email.com' |
Insert a Single Row
-- Insert with explicit column names (recommended)
INSERT INTO customers (first_name, last_name, email, city)
VALUES ('Alice', 'Johnson', 'alice@email.com', 'New York');
-- Insert with all columns (order matters!)
INSERT INTO customers
VALUES (1, 'Bob', 'Smith', 'bob@email.com', 'Los Angeles', 'CA', '2024-01-15', 1);
Always specify column names explicitly. It makes your queries readable and protects against errors if the table structure changes (columns added, reordered, or removed).
Column Order Matters
Insert Multiple Rows
DfBulk Insert
Inserting multiple rows in a single INSERT statement using comma-separated value lists. More efficient than single-row inserts because it reduces network round trips to the database.
-- Efficient: Insert multiple rows in one statement
INSERT INTO customers (first_name, last_name, email, city)
VALUES
('Bob', 'Smith', 'bob@email.com', 'Los Angeles'),
('Carol', 'Williams', 'carol@email.com', 'Chicago'),
('Dan', 'Brown', 'dan@email.com', 'Houston'),
('Eve', 'Davis', 'eve@email.com', 'Seattle'),
('Frank', 'Miller', 'frank@email.com', 'Denver');
Performance Comparison
| Method | Round Trips | Speed | Use Case |
|---|---|---|---|
| Single INSERT | N | Slow | 1-5 rows |
| Multiple VALUES | 1 | Fast | 5-1000 rows |
| INSERT...SELECT | 1 | Fastest | Bulk copy |
INSERT INTO ... SELECT
DfINSERT...SELECT
A statement that inserts the result set of a SELECT query into another table. Useful for copying data, creating backups, or populating derived tables.
-- Copy customers from New York to archive
INSERT INTO archive_customers (first_name, last_name, email)
SELECT first_name, last_name, email
FROM customers
WHERE city = 'New York';
-- Copy with transformations
INSERT INTO customer_summary (full_name, email_domain)
SELECT
first_name || ' ' || last_name AS full_name,
SUBSTR(email, INSTR(email, '@') + 1) AS email_domain
FROM customers
WHERE is_active = TRUE;
INSERT with Expressions
-- Use expressions to compute values
INSERT INTO products (name, price, discounted_price, stock, category)
VALUES (
'Laptop',
999.99,
999.99 * 0.9, -- 10% discount
50,
'Electronics'
);
-- Use subqueries
INSERT INTO product_stats (category, avg_price, total_stock)
SELECT
category,
AVG(price),
SUM(stock)
FROM products
GROUP BY category;
INSERT with NULL Values
-- Explicit NULL
INSERT INTO customers (first_name, last_name, email, phone)
VALUES ('Alice', 'Johnson', 'alice@email.com', NULL);
-- Implicit NULL (omit column)
INSERT INTO customers (first_name, last_name, email)
VALUES ('Bob', 'Smith', 'bob@email.com');
-- phone will be NULL (if no DEFAULT defined)
-- Check for NULL after insert
SELECT * FROM customers WHERE phone IS NULL;
INSERT with DEFAULT Values
-- Let defaults apply automatically
INSERT INTO orders (customer_id, product_id, quantity)
VALUES (1, 5, 2);
-- order_date, status, total use defaults
-- Explicitly use DEFAULT
INSERT INTO orders (customer_id, product_id, quantity, status)
VALUES (1, 5, 2, DEFAULT);
-- status will use its DEFAULT value
-- Mix explicit and default values
INSERT INTO products (name, price, stock, category)
VALUES ('Mouse', 29.99, DEFAULT, 'Electronics');
INSERT with Constraints
INSERT operations fail if they violate any constraint β NOT NULL, UNIQUE, CHECK, or FOREIGN KEY. The database rejects the entire statement and no data is inserted.
-- Example with multiple constraints
CREATE TABLE employees (
id INTEGER PRIMARY KEY AUTO_INCREMENT,
first_name TEXT NOT NULL,
last_name TEXT NOT NULL,
email TEXT UNIQUE NOT NULL,
salary DECIMAL(10,2) CHECK (salary >= 30000),
department TEXT DEFAULT 'General',
hire_date DATE DEFAULT CURRENT_DATE
);
-- This will succeed
INSERT INTO employees (first_name, last_name, email, salary)
VALUES ('Alice', 'Johnson', 'alice@company.com', 75000);
-- This will FAIL (duplicate email)
INSERT INTO employees (first_name, last_name, email, salary)
VALUES ('Bob', 'Smith', 'alice@company.com', 65000);
-- Error: UNIQUE constraint failed: employees.email
-- This will FAIL (salary too low)
INSERT INTO employees (first_name, last_name, email, salary)
VALUES ('Carol', 'Williams', 'carol@company.com', 25000);
-- Error: CHECK constraint failed: employees.salary
INSERT with Transactions
DfTransaction
A sequence of database operations treated as a single logical unit. Either all operations succeed (COMMIT) or none of them take effect (ROLLBACK), ensuring data consistency.
-- Use transactions for related inserts
BEGIN TRANSACTION;
INSERT INTO customers (first_name, last_name, email)
VALUES ('Alice', 'Johnson', 'alice@email.com');
INSERT INTO orders (customer_id, product_id, quantity, total)
VALUES (LAST_INSERT_ID(), 1, 2, 59.98);
COMMIT;
-- If any insert fails, ROLLBACK to undo all changes
Common Errors
-- ERROR: Column count doesn't match value count
INSERT INTO customers (first_name, last_name)
VALUES ('Alice', 'Johnson', 'alice@email.com');
-- 2 columns, 3 values
-- ERROR: Data type mismatch
INSERT INTO customers (age)
VALUES ('twenty-five'); -- age is INTEGER, not TEXT
-- ERROR: NOT NULL violation
INSERT INTO customers (email)
VALUES ('alice@email.com'); -- first_name and last_name are NOT NULL
-- ERROR: UNIQUE violation
INSERT INTO customers (email)
VALUES ('existing@email.com'); -- email already exists
Database Specific Features
-- MySQL: INSERT IGNORE (skip duplicates)
INSERT IGNORE INTO customers (email, name)
VALUES ('alice@email.com', 'Alice');
-- MySQL: INSERT...ON DUPLICATE KEY UPDATE
INSERT INTO inventory (product_id, quantity)
VALUES (1, 10)
ON DUPLICATE KEY UPDATE quantity = quantity + 10;
-- PostgreSQL: INSERT...ON CONFLICT
INSERT INTO customers (email, name)
VALUES ('alice@email.com', 'Alice')
ON CONFLICT (email)
DO UPDATE SET name = EXCLUDED.name;
-- SQL Server: INSERT with OUTPUT
INSERT INTO customers (name, email)
OUTPUT INSERTED.id, INSERTED.name
VALUES ('Alice', 'alice@email.com');
Performance Tips
For large data loads, batch your inserts (100-1000 rows at a time), disable indexes during load and rebuild afterward, and wrap everything in a transaction for maximum throughput.
Summary
Key Takeaways
- INSERT INTO adds new rows to a table
- Always specify column names for clarity and safety
- Insert multiple rows at once with comma-separated VALUES for better performance
- INSERT INTO...SELECT copies and transforms data between tables
- Column count must match value count, and all values must satisfy constraints