Medium severityquery
MySQL Error:
1248
What does this error mean?
MySQL error 1248 is thrown at parse time when a subquery in the FROM clause lacks an alias. MySQL treats every subquery in FROM as a derived table — a temporary result set that must be addressable by name in the outer query. Without an alias, the query planner cannot reference the result set and rejects the statement immediately with 'Every derived table must have its own alias'. In a data pipeline context this means an ADF Copy or Lookup activity, a dbt model, or an Airflow task running a MySQL source query fails at the first execution attempt — no rows are transferred and downstream tables never receive new data.
Common causes
- 1Subquery in FROM clause without an AS clause: `SELECT * FROM (SELECT id, created_at FROM orders WHERE status = 'open')` — MySQL rejects this immediately at parse time before touching any data.
- 2SQL ported from SQL Server or PostgreSQL where derived table aliases are optional syntax: those engines accept anonymous subqueries in FROM; MySQL does not and will error on every such query.
- 3BI tool or ORM auto-generated SQL that omits the alias. Power BI DirectQuery, Tableau, and older versions of SQLAlchemy have all been known to generate alias-free derived tables against MySQL sources.
- 4Nested subqueries where only the outermost level has an alias: `SELECT * FROM (SELECT * FROM (SELECT id FROM t) AS inner_q)` — the outer subquery is still missing its alias and MySQL errors on that level.
- 5dbt macros or Jinja-templated SQL that conditionally builds a derived table but forgets to append the alias token when the branch is taken.
- 6UNION or INTERSECT wrapped in a subquery without an alias: `SELECT * FROM (SELECT a FROM t1 UNION SELECT a FROM t2)` — the UNION result is itself a derived table and requires an alias.
- 7Hand-written migration scripts that concatenate SQL strings dynamically and drop the alias in the string join logic, causing intermittent failures depending on runtime parameter values.
How to fix it
- 1Step 1: Run the failing query directly in a MySQL client to confirm error 1248 and locate the exact subquery. The error message does not include a line number, so scan every FROM clause: `mysql -u user -p -e "EXPLAIN SELECT ..."` — EXPLAIN also triggers the parser and will surface the error.
- 2Step 2: Add AS alias_name immediately after the closing parenthesis of each subquery in the FROM clause: `SELECT * FROM (SELECT id, created_at FROM orders WHERE status = 'open') AS open_orders;`
- 3Step 3: For nested subqueries, alias every level independently: `SELECT outer_q.id FROM (SELECT inner_q.id FROM (SELECT id FROM orders) AS inner_q WHERE inner_q.id > 100) AS outer_q;`
- 4Step 4: If the query originates from a BI tool, check the tool's MySQL dialect setting. In Tableau: Data → Edit Connection → set database dialect to MySQL. In Power BI: change the native query in Power Query Editor and add the alias manually in Advanced Editor.
- 5Step 5: For MySQL 8.0+, refactor deeply nested derived tables into CTEs to eliminate the aliasing problem at the structural level: `WITH open_orders AS (SELECT id, created_at FROM orders WHERE status = 'open'), recent AS (SELECT id FROM open_orders WHERE created_at > NOW() - INTERVAL 7 DAY) SELECT * FROM recent;` — CTEs are referenced by their WITH-clause name and never need a separate AS alias.
- 6Step 6: In dbt, if the error occurs during a model run (`dbt run --select model_name`), inspect the compiled SQL in `target/compiled/` to see the exact query MySQL receives. Edit the source model or macro to include the alias, then rerun.
- 7Step 7: In ADF, open the pipeline → select the failing Copy or Lookup activity → Source tab → paste the corrected query into the Query field. Trigger a debug run to verify the fix before publishing.
Example log output
ERROR 1248 (42000): Every derived table must have its own alias
[ADF] Activity 'LookupOrderSummary' failed: ErrorCode=UserErrorOdbcOperationFailed, Message=ERROR [42000] [MySQL][ODBC 8.0(w) Driver][mysqld-8.0.32]Every derived table must have its own alias