Files
awesome-copilot/skills/reviewing-oracle-to-postgres-migration/references/oracle-parentheses-from-clause.md
PrimedPaul 623083f7b1 Adds the 'Oracle-to-PostgreSQL Migration Expert' Custom Agent, Asociated Skills, and Plugin Manifest (#950)
* Add the 'Oracle-to-PostgreSQL Migration Expert' Custom Agent, its associated skills, plugin manifest

* Update READMEs using 'npm run build'

* Resolve PR comments:
- Fix BOM characters
- Rerun 'npm run build'
- Clarify timestampz date kind
- Remove consufing text for SELECT INTO exception
- Remove dangerous VB.NET example

* Update README and refcursor handling documentation for clarity and consistency

* Update skills/creating-oracle-to-postgres-master-migration-plan/SKILL.md

Add .slnx to discovery of projects

Co-authored-by: Aaron Powell <me@aaron-powell.com>

---------

Co-authored-by: TCPrimedPaul <paul.delannoy@tc.gc.ca>
Co-authored-by: Aaron Powell <me@aaron-powell.com>
2026-03-11 10:46:06 +11:00

191 lines
4.8 KiB
Markdown

# Oracle to PostgreSQL: Parentheses in FROM Clause
## Contents
- Problem
- Root Cause
- Solution Pattern
- Examples
- Migration Checklist
- Common Locations
- Application Code Examples
- Error Messages to Watch For
- Testing Recommendations
## Problem
Oracle allows optional parentheses around table names in the FROM clause:
```sql
-- Oracle: Both are valid
SELECT * FROM (TABLE_NAME) WHERE id = 1;
SELECT * FROM TABLE_NAME WHERE id = 1;
```
PostgreSQL does **not** allow extra parentheses around a single table name in the FROM clause without it being a derived table or subquery. Attempting to use this pattern results in:
```
Npgsql.PostgresException: 42601: syntax error at or near ")"
```
## Root Cause
- **Oracle**: Treats `FROM(TABLE_NAME)` as equivalent to `FROM TABLE_NAME`
- **PostgreSQL**: Parentheses in the FROM clause are only valid for:
- Subqueries: `FROM (SELECT * FROM table)`
- Explicit table references that are part of join syntax
- Common Table Expressions (CTEs)
- Without a valid SELECT or join context, PostgreSQL raises a syntax error
## Solution Pattern
Remove the unnecessary parentheses around the table name:
```sql
-- Oracle (problematic in PostgreSQL)
SELECT col1, col2
FROM (TABLE_NAME)
WHERE id = 1;
-- PostgreSQL (correct)
SELECT col1, col2
FROM TABLE_NAME
WHERE id = 1;
```
## Examples
### Example 1: Simple Table Reference
```sql
-- Oracle
SELECT employee_id, employee_name
FROM (EMPLOYEES)
WHERE department_id = 10;
-- PostgreSQL (fixed)
SELECT employee_id, employee_name
FROM EMPLOYEES
WHERE department_id = 10;
```
### Example 2: Join with Parentheses
```sql
-- Oracle (problematic)
SELECT e.employee_id, d.department_name
FROM (EMPLOYEES) e
JOIN (DEPARTMENTS) d ON e.department_id = d.department_id;
-- PostgreSQL (fixed)
SELECT e.employee_id, d.department_name
FROM EMPLOYEES e
JOIN DEPARTMENTS d ON e.department_id = d.department_id;
```
### Example 3: Valid Subquery Parentheses (Works in Both)
```sql
-- Both Oracle and PostgreSQL
SELECT *
FROM (SELECT employee_id, employee_name FROM EMPLOYEES WHERE department_id = 10) sub;
```
## Migration Checklist
When fixing this issue, verify:
1. **Identify all problematic FROM clauses**:
- Search for `FROM (` pattern in SQL
- Verify the opening parenthesis is immediately after `FROM` followed by a table name
- Confirm it's **not** a subquery (no SELECT keyword inside)
2. **Distinguish valid parentheses**:
-`FROM (SELECT ...)` - Valid subquery
-`FROM (table_name` followed by a join - Check if JOIN keyword follows
-`FROM (TABLE_NAME)` - Invalid, remove parentheses
3. **Apply the fix**:
- Remove the parentheses around the table name
- Keep parentheses for legitimate subqueries
4. **Test thoroughly**:
- Execute the query in PostgreSQL
- Verify result set matches original Oracle query
- Include in integration tests
## Common Locations
Search for `FROM (` in:
- ✅ Stored procedures and functions (DDL scripts)
- ✅ Application data access layers (DAL classes)
- ✅ Dynamic SQL builders
- ✅ Reporting queries
- ✅ Views and materialized views
- ✅ Complex queries with multiple joins
## Application Code Examples
### VB.NET
```vb
' Before (Oracle)
StrSQL = "SELECT employee_id, NAME " _
& "FROM (EMPLOYEES) e " _
& "WHERE e.department_id = 10"
' After (PostgreSQL)
StrSQL = "SELECT employee_id, NAME " _
& "FROM EMPLOYEES e " _
& "WHERE e.department_id = 10"
```
### C #
```csharp
// Before (Oracle)
var sql = "SELECT id, name FROM (USERS) WHERE status = @status";
// After (PostgreSQL)
var sql = "SELECT id, name FROM USERS WHERE status = @status";
```
## Error Messages to Watch For
```
Npgsql.PostgresException: 42601: syntax error at or near ")"
ERROR: syntax error at or near ")"
LINE 1: SELECT * FROM (TABLE_NAME) WHERE ...
^
```
## Testing Recommendations
1. **Syntax Verification**: Parse all migrated queries to ensure they run without syntax errors
```csharp
[Fact]
public void GetEmployees_ExecutesWithoutSyntaxError()
{
// Should not throw PostgresException with error code 42601
var employees = dal.GetEmployees(departmentId: 10);
Assert.NotEmpty(employees);
}
```
2. **Result Comparison**: Verify that result sets are identical before and after migration
3. **Regex-based Search**: Use pattern `FROM\s*\(\s*[A-Za-z_][A-Za-z0-9_]*\s*\)` to identify candidates
## Related Files
- Reference: [oracle-to-postgres-type-coercion.md](oracle-to-postgres-type-coercion.md) - Other syntax differences
- PostgreSQL Documentation: [SELECT Statement](https://www.postgresql.org/docs/current/sql-select.html)
## Migration Notes
- This is a straightforward syntactic fix with no semantic implications
- No data conversion required
- Safe to apply automated find-and-replace, but manually verify complex queries
- Update integration tests to exercise the migrated queries