SQL INSERT INTO
Complete SQL INSERT INTO Technical Guide
1. Fundamental Syntax
Explicit Column Listing:
INSERT INTO table_name (col1, col2, col3) VALUES (val1, val2, val3);
Implicit Column Listing:
INSERT INTO table_name VALUES (val1, val2, val3);
2. Advanced Insert Methods
Multi-Row Insert
INSERT INTO products (name, price) VALUES ('Product A', 9.99), ('Product B', 19.99), ('Product C', 29.99);
More efficient than single inserts (reduced roundtrips)
Insert from Select
INSERT INTO archived_orders SELECT * FROM orders WHERE order_date < '2020-01-01';
Insert with Defaults
INSERT INTO users (username) VALUES ('johndoe'); -- Other columns get DEFAULT values
3. Database-Specific Features
MySQL
INSERT IGNORE INTO table ... -- Skips rows with errors
INSERT INTO table ... ON DUPLICATE KEY UPDATE ... -- Updates if duplicate exists
PostgreSQL
INSERT INTO table ... RETURNING id -- Returns generated values
INSERT INTO table ... ON CONFLICT DO NOTHING -- Handles conflicts gracefully
4. Performance Considerations
Batch Insert Optimization
- Use multi-row VALUES syntax
- Consider prepared statements
- Batch size typically 100-1000 rows
Index Impact
- Each index adds insert overhead
- Consider dropping/recreating indexes for bulk loads
- Foreign keys add validation cost
Bulk Load Techniques
-- MySQL LOAD DATA INFILE '/path/to/file.csv' INTO TABLE my_table FIELDS TERMINATED BY ','; -- PostgreSQL COPY my_table FROM '/path/to/file.csv' DELIMITER ',';
5. Error Handling
Common Errors
- Constraint violations (PK, FK, UNIQUE)
- Data type mismatches
- NOT NULL constraint violations
Handling Strategies
- Use database-specific modifiers (IGNORE, ON CONFLICT)
- Validate data before insert
- Use transactions for atomicity
6. Advanced Patterns
Insert with Joins
INSERT INTO user_orders (user_id, order_id) SELECT u.id, o.id FROM users u JOIN orders o ON u.email = o.customer_email;
Conditional Insert
INSERT INTO inventory SELECT product_id, quantity FROM shipment WHERE quantity > 0;
Insert with CTEs
WITH new_users AS ( SELECT * FROM temp_users WHERE valid = true ) INSERT INTO main_users SELECT * FROM new_users;
RETURNING Clause
INSERT INTO users (name, email) VALUES ('Alice', 'alice@example.com') RETURNING id, created_at;
Supported in PostgreSQL, Oracle, and SQLite. Useful for getting auto-generated values.
Bulk Insert Optimization
- Transaction Batching: Wrap multiple inserts in a single transaction
- Batch Size: Optimal sizes vary (typically 500-5000 rows per batch)
- Disable Constraints: Temporarily disable triggers/checks during bulk loads
-- SQL Server example BEGIN TRANSACTION; INSERT INTO table VALUES (...); INSERT INTO table VALUES (...); COMMIT;
Conflict Handling
MySQL
INSERT INTO table (id, name) VALUES (1, 'Alice') ON DUPLICATE KEY UPDATE name='Alice';
PostgreSQL
INSERT INTO table (id, name) VALUES (1, 'Alice') ON CONFLICT (id) DO UPDATE SET name=EXCLUDED.name;
Generated/Virtual Columns
-- MySQL example CREATE TABLE products ( id INT PRIMARY KEY, price DECIMAL(10,2), tax DECIMAL(10,2) GENERATED ALWAYS AS (price * 0.1) ); -- Insert ignores generated columns INSERT INTO products (id, price) VALUES (1, 100.00);
Security Best Practices
- Use Prepared Statements to prevent SQL injection
- Validate Input before insertion
- Limit Permissions: Application users shouldn't have full write access
-- Parameterized query example (Python) cursor.execute( "INSERT INTO users (name) VALUES (%s)", (user_input,) )
Partitioned Table Inserts
-- PostgreSQL example INSERT INTO sales (sale_date, amount) VALUES ('2023-01-15', 99.99) -- Automatically routes to correct partition
Requires proper partition key in INSERT values
Materialized View Impact
-- After bulk inserts REFRESH MATERIALIZED VIEW CONCURRENTLY sales_summary;
Large inserts may require manual refresh of dependent views