PostgreSQL Error 42701: Duplicate Column
PostgreSQL error code 42701 (duplicate_column) occurs when a column name appears more than once in a table definition, an ALTER TABLE statement, or a query result set. PostgreSQL strictly enforces column name uniqueness within any single table or result set, and it will immediately abort the operation upon detecting a duplicate. This error is especially common during database migrations, schema refactoring, and complex JOIN queries.
Top 3 Causes
1. Adding an Already-Existing Column with ALTER TABLE
This is the most frequent cause, typically triggered when a migration script runs more than once or when two team members independently add the same column.
-- Triggers 42701 if 'email' already exists
ALTER TABLE users ADD COLUMN email VARCHAR(255);
-- Safe fix: use IF NOT EXISTS (PostgreSQL 9.6+)
ALTER TABLE users ADD COLUMN IF NOT EXISTS email VARCHAR(255);
-- Alternative: check before altering (compatible with older versions)
DO $$
BEGIN
IF NOT EXISTS (
SELECT 1 FROM information_schema.columns
WHERE table_schema = 'public'
AND table_name = 'users'
AND column_name = 'email'
) THEN
ALTER TABLE users ADD COLUMN email VARCHAR(255);
END IF;
END;
$$;
2. Duplicate Column Names in CREATE TABLE
Copy-paste mistakes or collaborative editing can lead to the same column name being declared twice in a single CREATE TABLE statement.
-- Triggers 42701: user_id is declared twice
CREATE TABLE orders (
order_id SERIAL PRIMARY KEY,
user_id INT NOT NULL,
product_id INT NOT NULL,
user_id INT -- ERROR: duplicate column!
);
-- Fix: remove the duplicate column
CREATE TABLE orders (
order_id SERIAL PRIMARY KEY,
user_id INT NOT NULL,
product_id INT NOT NULL,
created_at TIMESTAMP DEFAULT NOW()
);
3. Ambiguous Columns in JOINs and View Definitions
Using SELECT * across JOINed tables or explicitly selecting the same column twice causes duplicate column names in the result set, which fails when used inside CREATE VIEW or CREATE MATERIALIZED VIEW.
-- Triggers 42701 if both tables share columns like 'id' or 'created_at'
CREATE VIEW order_summary AS
SELECT o.*, u.*
FROM orders o
JOIN users u ON o.user_id = u.id;
-- Fix: explicitly name and alias each column
CREATE VIEW order_summary AS
SELECT
o.order_id,
o.product_id,
o.created_at AS order_created_at,
u.id AS user_id,
u.email AS user_email,
u.created_at AS user_created_at
FROM orders o
JOIN users u ON o.user_id = u.id;
Quick Fix Solutions
- Use
ADD COLUMN IF NOT EXISTSfor all migration scripts. - Always use explicit column aliases when writing JOINs.
- Audit your table structure before modifying it:
-- Check existing columns before making changes
SELECT column_name, data_type
FROM information_schema.columns
WHERE table_schema = 'public'
AND table_name = 'your_table'
ORDER BY ordinal_position;
Prevention Tips
1. Write idempotent migration scripts. Every DDL script should be safe to run multiple times. Use IF NOT EXISTS guards consistently and adopt migration tools like Flyway or Liquibase to track applied changes.
-- Idempotent migration example
ALTER TABLE users ADD COLUMN IF NOT EXISTS phone VARCHAR(20);
CREATE INDEX IF NOT EXISTS idx_users_email ON users(email);
2. Avoid SELECT * in views and persistent queries. Always specify column names explicitly and use aliases to prevent naming conflicts, especially in JOIN-heavy queries. This makes your code more readable and immune to schema changes that could introduce duplicate column names.
Related Errors
| Code | Name | Description |
|---|---|---|
| 42P07 | duplicate_table |
Creating a table that already exists; use CREATE TABLE IF NOT EXISTS
|
| 42710 | duplicate_object |
Duplicate index, sequence, or type; use IF NOT EXISTS variants |
| 42P16 | invalid_table_definition |
Malformed table definition, often appears alongside 42701 |
📖 Want a more detailed guide?
Check out the full in-depth version (Korean) on oraerror.com — includes detailed analysis, additional SQL examples, and prevention tips.
Top comments (0)