Skip to content

ORA-00907 Missing Right Parenthesis - SQL Syntax Error Resolution

Error Text: ORA-00907: missing right parenthesis

This error occurs when Oracle SQL parser encounters unbalanced parentheses in a SQL statement. It’s one of the most common SQL syntax errors, typically caused by missing closing parentheses, incorrect comma placement, or malformed SQL constructs.

-- Function calls
SELECT SUBSTR(column_name, 1, 10) FROM table_name;
-- Subqueries
SELECT * FROM table1 WHERE id IN (SELECT id FROM table2);
-- Complex conditions
SELECT * FROM table1 WHERE (col1 = 'A' AND col2 = 'B') OR (col3 = 'C');
-- Table joins with conditions
SELECT * FROM table1 t1 JOIN table2 t2 ON (t1.id = t2.id);
-- INSERT statements
INSERT INTO table1 (col1, col2) VALUES (val1, val2);
  • Every opening parenthesis ( must have a matching closing parenthesis )
  • Nested parentheses must be properly balanced
  • Function parameters must be enclosed in parentheses
  • Subqueries must be enclosed in parentheses
-- Missing closing parenthesis in function
SELECT SUBSTR(column_name, 1, 10 FROM table_name; -- ERROR
-- Missing closing parenthesis in subquery
SELECT * FROM table1 WHERE id IN (SELECT id FROM table2; -- ERROR
-- Missing closing parenthesis in complex condition
SELECT * FROM table1 WHERE (col1 = 'A' AND col2 = 'B'; -- ERROR
-- Correct function syntax
SELECT SUBSTR(column_name, 1, 10) FROM table_name;
-- Correct subquery syntax
SELECT * FROM table1 WHERE id IN (SELECT id FROM table2);
-- Correct complex condition syntax
SELECT * FROM table1 WHERE (col1 = 'A' AND col2 = 'B');
-- Missing comma in column list
SELECT col1 col2, col3 FROM table_name; -- ERROR
-- Extra comma in column list
SELECT col1, col2, FROM table_name; -- ERROR
-- Missing closing parenthesis in INSERT
INSERT INTO table1 (col1, col2 VALUES (val1, val2); -- ERROR
-- Correct column list with commas
SELECT col1, col2, col3 FROM table_name;
-- Remove trailing comma
SELECT col1, col2 FROM table_name;
-- Complete INSERT statement
INSERT INTO table1 (col1, col2) VALUES (val1, val2);
-- Missing parentheses around subquery
SELECT * FROM table1 WHERE id IN SELECT id FROM table2; -- ERROR
-- Incomplete subquery parentheses
SELECT * FROM table1 WHERE EXISTS (SELECT 1 FROM table2 WHERE table2.id = table1.id; -- ERROR
-- Malformed correlated subquery
SELECT * FROM table1 t1 WHERE t1.amount > (SELECT AVG(amount FROM table2 t2); -- ERROR
-- Proper subquery parentheses
SELECT * FROM table1 WHERE id IN (SELECT id FROM table2);
-- Complete EXISTS subquery
SELECT * FROM table1 WHERE EXISTS (SELECT 1 FROM table2 WHERE table2.id = table1.id);
-- Correct correlated subquery
SELECT * FROM table1 t1 WHERE t1.amount > (SELECT AVG(amount) FROM table2 t2);
-- Missing closing parenthesis in ON clause
SELECT * FROM table1 t1 JOIN table2 t2 ON (t1.id = t2.id AND t1.status = 'A'; -- ERROR
-- Incorrect JOIN syntax
SELECT * FROM table1 JOIN table2 ON t1.id = t2.id AND (t1.type = 'X'; -- ERROR
-- Correct JOIN with balanced parentheses
SELECT * FROM table1 t1 JOIN table2 t2 ON (t1.id = t2.id AND t1.status = 'A');
-- Alternative JOIN syntax without extra parentheses
SELECT * FROM table1 t1 JOIN table2 t2 ON t1.id = t2.id AND t1.type = 'X';
-- Break down complex query to identify imbalance
-- Original problematic query:
SELECT col1,
(SELECT COUNT(*) FROM table2 WHERE id = table1.id, -- Missing closing parenthesis
col3
FROM table1;
-- Fixed query:
SELECT col1,
(SELECT COUNT(*) FROM table2 WHERE id = table1.id), -- Added closing parenthesis
col3
FROM table1;
-- Start with basic query structure
SELECT col1 FROM table1;
-- Add components one by one
SELECT col1, col2 FROM table1;
-- Add WHERE clause
SELECT col1, col2 FROM table1 WHERE condition;
-- Add subqueries
SELECT col1, col2 FROM table1 WHERE id IN (SELECT id FROM table2);
-- Check function syntax
-- Wrong:
SELECT DECODE(status 'A', 'Active', 'Inactive') FROM table1; -- Missing comma
-- Correct:
SELECT DECODE(status, 'A', 'Active', 'Inactive') FROM table1;
-- Complex function nesting
SELECT SUBSTR(TRIM(UPPER(column_name)), 1, 10) FROM table1;
-- Problematic CASE statement
SELECT
CASE
WHEN col1 = 'A' THEN 'Active'
WHEN col1 = 'I' THEN 'Inactive'
ELSE 'Unknown'
-- Missing END
FROM table1;
-- Correct CASE statement
SELECT
CASE
WHEN col1 = 'A' THEN 'Active'
WHEN col1 = 'I' THEN 'Inactive'
ELSE 'Unknown'
END as status
FROM table1;
-- Missing parentheses in window function
SELECT
col1,
ROW_NUMBER() OVER ORDER BY col2 -- Missing parentheses
FROM table1;
-- Correct window function syntax
SELECT
col1,
ROW_NUMBER() OVER (ORDER BY col2)
FROM table1;
-- Missing parentheses in CTE
WITH cte_name AS
SELECT col1, col2 FROM table1 WHERE condition -- Missing parentheses
SELECT * FROM cte_name;
-- Correct CTE syntax
WITH cte_name AS (
SELECT col1, col2 FROM table1 WHERE condition
)
SELECT * FROM cte_name;
-- Use SQL formatting tools to identify structure issues
-- Before formatting (hard to read):
SELECT col1,(SELECT COUNT(*)FROM table2 WHERE id=table1.id,col3 FROM table1;
-- After formatting (easier to spot missing parenthesis):
SELECT col1,
(SELECT COUNT(*)
FROM table2
WHERE id = table1.id, -- Missing closing parenthesis here
col3
FROM table1;
-- Manual counting technique:
-- SELECT col1, (SELECT COUNT(*) FROM table2 WHERE id = table1.id), col3 FROM table1;
-- ^ ^
-- 1 1 -- Balanced
-- SELECT col1, (SELECT COUNT(*) FROM table2 WHERE id = table1.id, col3 FROM table1;
-- ^
-- 1 -- Unbalanced (missing closing)
-- Create a simple validation procedure
CREATE OR REPLACE PROCEDURE validate_sql(p_sql CLOB) AS
l_cursor NUMBER;
BEGIN
l_cursor := DBMS_SQL.OPEN_CURSOR;
DBMS_SQL.PARSE(l_cursor, p_sql, DBMS_SQL.NATIVE);
DBMS_OUTPUT.PUT_LINE('SQL is valid');
DBMS_SQL.CLOSE_CURSOR(l_cursor);
EXCEPTION
WHEN OTHERS THEN
DBMS_OUTPUT.PUT_LINE('SQL Error: ' || SQLERRM);
IF DBMS_SQL.IS_OPEN(l_cursor) THEN
DBMS_SQL.CLOSE_CURSOR(l_cursor);
END IF;
END;
/
-- Use consistent indentation and line breaks
SELECT
t1.col1,
t1.col2,
(SELECT COUNT(*)
FROM table2 t2
WHERE t2.id = t1.id) as count_col,
t1.col3
FROM table1 t1
WHERE t1.status = 'A'
AND t1.created_date > SYSDATE - 30;
-- Always include parentheses for functions, even with no parameters
SELECT SYSDATE() FROM dual; -- Some databases require this
SELECT USER() FROM dual; -- Better to be explicit
-- Use clear parameter separation
SELECT SUBSTR(column_name, 1, 10),
DECODE(status, 'A', 'Active', 'I', 'Inactive', 'Unknown'),
NVL(description, 'No Description')
FROM table_name;
-- Format subqueries for clarity
SELECT *
FROM table1
WHERE id IN (
SELECT id
FROM table2
WHERE status = 'ACTIVE'
AND created_date > SYSDATE - 7
);
-- Break down complex queries into parts
-- Original complex query with error:
SELECT
t1.id,
t1.name,
(SELECT COUNT(*) FROM orders o WHERE o.customer_id = t1.id AND o.status = 'COMPLETED',
(SELECT SUM(amount) FROM payments p WHERE p.customer_id = t1.id)
FROM customers t1;
-- Identify the issue: missing closing parenthesis in first subquery
-- Fixed version:
SELECT
t1.id,
t1.name,
(SELECT COUNT(*) FROM orders o WHERE o.customer_id = t1.id AND o.status = 'COMPLETED'),
(SELECT SUM(amount) FROM payments p WHERE p.customer_id = t1.id)
FROM customers t1;
-- Validate dynamic SQL before execution
DECLARE
l_sql VARCHAR2(4000);
l_cursor NUMBER;
BEGIN
l_sql := 'SELECT col1, (SELECT COUNT(*) FROM table2 WHERE id = table1.id FROM table1';
l_cursor := DBMS_SQL.OPEN_CURSOR;
BEGIN
DBMS_SQL.PARSE(l_cursor, l_sql, DBMS_SQL.NATIVE);
DBMS_OUTPUT.PUT_LINE('SQL is syntactically correct');
EXCEPTION
WHEN OTHERS THEN
DBMS_OUTPUT.PUT_LINE('Syntax Error: ' || SQLERRM);
END;
DBMS_SQL.CLOSE_CURSOR(l_cursor);
END;
/
  • ORA-00933: SQL command not properly ended
  • ORA-00936: Missing expression
  • ORA-00904: Invalid identifier
  • ORA-01756: Quoted string not properly terminated
  1. Use consistent SQL formatting and indentation
  2. Validate parentheses balance before execution
  3. Test complex queries in parts
  4. Use SQL development tools with syntax highlighting
  5. Implement code review processes
  6. Keep subqueries simple and readable
  • Count opening and closing parentheses
  • Check function parameter syntax
  • Verify subquery parentheses
  • Validate JOIN clause syntax
  • Review CASE statement structure
  • Check for missing commas
  • Verify CTE syntax
  • Test query components individually