How to fix syntax error at or near 'UNION' in PostgreSQL

PostgreSQLINTERMEDIATEMEDIUMUpdated Dec 25, 2025ยท 212 views

The PostgreSQL "syntax error at or near UNION" occurs when a UNION query is malformed, typically due to ORDER BY or LIMIT clauses appearing before UNION, mismatched column counts, incompatible data types, or missing parentheses around subqueries. Fixing requires understanding proper UNION syntax and ensuring all SELECT statements match in structure.

Quick fix

Fixes syntax error at or near 'UNION'

-- INCORRECT: ORDER BY before UNION
SELECT id, name FROM users ORDER BY id
UNION
SELECT id, name FROM archived_users;

-- CORRECT: ORDER BY and LIMIT after UNION
SELECT id, name FROM users
UNION
SELECT id, name FROM archived_users
ORDER BY id
LIMIT 10;
  1. Check for ORDER BY or LIMIT before UNION
  2. Verify consistent parentheses around all subqueries
  3. Check column count and order across all SELECT statements
  4. Verify column data types are compatible
postgresql โ€” error
-- INCORRECT: ORDER BY before UNION
SELECT id, name FROM users ORDER BY id
UNION
SELECT id, name FROM archived_users;
-- CORRECT: ORDER BY and LIMIT after UNION
SELECT id, name FROM users
UNION
SELECT id, name FROM archived_users
ORDER BY id
LIMIT 10;
syntax error at or near 'UNION'

What this error means

PostgreSQL raises a syntax error when the UNION operator is not used correctly in a query. UNION combines result sets from multiple SELECT statements, but they must follow strict syntactic rules: all SELECT statements must have the same number of columns with compatible data types, ORDER BY and LIMIT must apply to the entire result set (not individual SELECT statements), and parentheses may be required to disambiguate the query structure. The error "syntax error at or near 'UNION'" typically appears during query parsing, before execution. PostgreSQL's parser encounters the UNION keyword in an unexpected position or context, preventing the query from being compiled. This is different from runtime errors that occur after parsing succeeds but during execution (like type mismatches). Common scenarios include: placing ORDER BY or LIMIT before UNION instead of after, wrapping a single SELECT with parentheses but not all of them in a multi-part UNION, using WITH (CTE) clauses without proper structure, or with query builders that generate malformed SQL.

Typical symptoms

  • Query execution fails immediately with parse-time syntax error
  • Database clients show "syntax error at or near UNION" in error message
  • Query works in one application but fails in another (often due to query builders)
  • Adding parentheses around one subquery but not others causes the error
  • Using ORDER BY or LIMIT on individual SELECT statements within UNION fails
  • Common table expressions (CTEs) combined with UNION produce syntax errors

Common causes

  1. ORDER BY or LIMIT clause placed before UNION instead of after the entire UNION expression
  2. Inconsistent parenthesization: some subqueries wrapped in parentheses but not others
  3. LIMIT clause in a query builder applied to individual SELECT before UNION combines results
  4. WITH clause (common table expression) not properly scoped within UNION context
  5. Different number of columns in SELECT statements being unioned together
  6. Misaligned SQL generation by query builders (Knex, SQLAlchemy, ORM libraries)
  7. Attempting to use ORDER BY with column names that are ambiguous across multiple SELECT statements

How to fix "syntax error at or near 'UNION'"

1Check for ORDER BY or LIMIT before UNION

The most common cause of this error is placing ORDER BY or LIMIT on an individual SELECT before combining with UNION.

sql
-- INCORRECT: ORDER BY before UNION
SELECT id, name FROM users ORDER BY id
UNION
SELECT id, name FROM archived_users;

-- CORRECT: ORDER BY and LIMIT after UNION
SELECT id, name FROM users
UNION
SELECT id, name FROM archived_users
ORDER BY id
LIMIT 10;

If you need to ORDER BY or LIMIT individual subqueries before combining them, wrap each in parentheses:

sql
(SELECT id, name FROM users ORDER BY id LIMIT 5)
UNION
(SELECT id, name FROM archived_users ORDER BY id LIMIT 5)
ORDER BY id;
2Verify consistent parentheses around all subqueries

When using parentheses, ensure all SELECT statements in the UNION are consistently parenthesized, especially with LIMIT, ORDER BY, or CTEs.

```sql
-- INCORRECT: Only first is wrapped
(SELECT id, name FROM users LIMIT 10)
UNION
SELECT id, name FROM archived_users;

-- CORRECT: Both wrapped consistently
(SELECT id, name FROM users LIMIT 10)
UNION
(SELECT id, name FROM archived_users LIMIT 10);

-- Also correct: Neither wrapped (when no LIMIT/ORDER BY per subquery)
SELECT id, name FROM users
UNION
SELECT id, name FROM archived_users;

3Check column count and order across all SELECT statements

All SELECT statements in a UNION must return the same number of columns in the same order.

```sql
-- INCORRECT: Different number of columns
SELECT id, name, email FROM users
UNION
SELECT id, name FROM archived_users; -- Only 2 columns

-- CORRECT: Same columns in same order
SELECT id, name, email FROM users
UNION
SELECT id, name, email FROM archived_users;

-- Or add NULL placeholders for missing columns:
SELECT id, name, email FROM users
UNION
SELECT id, name, NULL as email FROM archived_users;

4Verify column data types are compatible

PostgreSQL requires compatible data types across UNION columns. While type coercion may occur, mismatches can cause errors.

```sql
-- INCORRECT: Incompatible types (int vs text)
SELECT id::int, name FROM users
UNION
SELECT code::text, description FROM error_codes;

-- CORRECT: Explicit casting to ensure compatible types
SELECT id::text as code, name as description FROM users
UNION
SELECT code::text, description::text FROM error_codes;

-- Check result types with EXPLAIN:
EXPLAIN SELECT id, name FROM users UNION SELECT id, name FROM archived_users;

5Check for WITH clause scope issues

Common table expressions (WITH clauses) combined with UNION can cause syntax errors if not properly structured.

```sql
-- INCORRECT: WITH might not apply to second SELECT
WITH active_users AS (
SELECT id, name FROM users WHERE status = 'active'
)
SELECT * FROM active_users
UNION
SELECT id, name FROM archived_users; -- archived_users not in CTE scope

-- CORRECT: Include all referenced tables
WITH active_users AS (
SELECT id, name FROM users WHERE status = 'active'
),
archived AS (
SELECT id, name FROM archived_users
)
SELECT * FROM active_users
UNION
SELECT * FROM archived;

6Check if using a query builder and validate generated SQL

Query builders (Knex, SQLAlchemy, ORMs) may generate malformed UNION queries. Always validate the generated SQL.

javascript
// Example: Knex.js - ensure UNION is called correctly
const query = knex
  .select('id', 'name')
  .from('users')
  .union([
    knex.select('id', 'name').from('archived_users')
  ])
  .orderBy('id');

console.log(query.toString());  // Print SQL to verify it's correct

If the generated SQL looks wrong, consult the query builder's UNION documentation or switch to raw SQL if the builder is not flexible enough.

7Use UNION ALL if appropriate to improve performance

UNION removes duplicate rows (expensive operation), while UNION ALL keeps all rows (fast). If you don't need deduplication, use UNION ALL.

sql
-- UNION: removes duplicates (sorts results internally)
SELECT id, name FROM users
UNION
SELECT id, name FROM archived_users;  -- Slower

-- UNION ALL: keeps all rows (no sorting)
SELECT id, name FROM users
UNION ALL
SELECT id, name FROM archived_users;  -- Faster

Also check PostgreSQL documentation on query optimization: use EXPLAIN ANALYZE to see if UNION is the bottleneck.

Advanced notes

For complex UNION queries, use subqueries to improve readability and avoid syntax errors. Wrap the entire UNION expression in parentheses and apply ORDER BY at the outermost level:

sql
(
  SELECT id, name, 'active' as status FROM users WHERE status = 'active'
  UNION ALL
  SELECT id, name, 'archived' FROM archived_users
)
ORDER BY name
LIMIT 100;

When working with nested UNIONs (UNION of UNION results), ensure type resolution is unambiguous. PostgreSQL resolves types left-to-right, so if you have SELECT NULL UNION SELECT NULL UNION SELECT 1, the middle UNION outputs text type, then tries to combine text with integer on the outer UNION. Explicitly cast NULL to the desired type to avoid this:

sql
SELECT NULL::int
UNION
SELECT NULL::int
UNION
SELECT 1;

For performance-critical queries, consider UNION ALL over UNION to avoid the costly sort/deduplication step. If you need deduplication, use DISTINCT on a subquery instead:

sql
SELECT DISTINCT id, name FROM (
  SELECT id, name FROM users
  UNION ALL
  SELECT id, name FROM archived_users
) combined;

Use PostgreSQL's EXPLAIN and EXPLAIN ANALYZE to inspect the query plan and verify that UNION is being executed efficiently. Watch for sequential scans or external sorts that indicate missing indexes or table statistics issues.

Frequently asked questions

What does "syntax error at or near 'UNION'" mean?
PostgreSQL raises a syntax error when the UNION operator is not used correctly in a query. UNION combines result sets from multiple SELECT statements, but they must follow strict syntactic rules: all SELECT statements must have the same number of columns with compatible data types, ORDER BY and LIMIT must apply to the entire result set (not individual SELECT statements), and parentheses may be required to disambiguate the query structure. The error "syntax error at or near 'UNION'" typically appears during query parsing, before execution.
How do I fix "syntax error at or near 'UNION'"?
The PostgreSQL "syntax error at or near UNION" occurs when a UNION query is malformed, typically due to ORDER BY or LIMIT clauses appearing before UNION, mismatched column counts, incompatible data types, or missing parentheses around subqueries. Fixing requires understanding proper UNION syntax and ensuring all SELECT statements match in structure.
What causes "syntax error at or near 'UNION'"?
ORDER BY or LIMIT clause placed before UNION instead of after the entire UNION expression Inconsistent parenthesization: some subqueries wrapped in parentheses but not others LIMIT clause in a query builder applied to individual SELECT before UNION combines results
Is the "syntax error at or near 'UNION'" error serious?
It is a medium-severity error โ€” more of a blocker than a risk. The steps above resolve it.

Official resources & further reading