ERROR 1248 (42000): Every derived table must have its own alias is raised when a subquery used as a table in the FROM clause (a derived table) is not given an alias. The error symbol is ER_DERIVED_MUST_HAVE_ALIAS.
Impact
This is a syntax error caught at parse time — MySQL rejects the query before executing it. No rows are read or written, and no transaction is started. The error is immediate and deterministic: the same query will always fail until the alias is added.
Developers most commonly encounter this when writing complex reporting queries, refactoring a flat query into a subquery, or generating queries programmatically. ORMs that construct raw subquery expressions (Hibernate native queries, SQLAlchemy text(), ActiveRecord from with a literal string) will surface this as a database-level exception rather than an ORM-level validation error.
Common Causes
Subquery in FROM without an alias. A subquery placed directly in the
FROMclause has noAS alias_nameclause appended.Joining a subquery without an alias. The same rule applies when a subquery is used in a
JOINexpression — each subquery-derived relation must have an alias.CTEs confused with derived tables. Developers new to MySQL sometimes write a subquery where they intended a CTE (
WITHclause), forgetting that inline subqueries still need aliases even when a CTE would not require the alias on its own reference.Programmatically generated SQL. Query builders or templating code that assembles subquery fragments may omit the alias, especially when refactoring a literal table name to a subquery.
Nested subqueries missing an alias at any level. Each subquery at every nesting level that appears in a
FROMorJOINposition requires its own alias — not just the outermost one.
Troubleshooting and Resolution Steps
Identify the unaliased subquery. MySQL's error message does not point to a line number, so scan your
FROMandJOINclauses for any(SELECT ...)that lacks anAS <name>suffix.Failing query:
SELECT dept, total FROM ( SELECT department AS dept, SUM(salary) AS total FROM employees GROUP BY department );Fix — add an alias after the closing parenthesis:
SELECT dept, total FROM ( SELECT department AS dept, SUM(salary) AS total FROM employees GROUP BY department ) AS dept_totals;Fix subqueries used in JOIN clauses. The alias requirement applies equally to joined subqueries.
Failing query:
SELECT e.name, s.total FROM employees e JOIN ( SELECT employee_id, SUM(amount) AS total FROM sales GROUP BY employee_id ) ON e.id = employee_id;Fix:
SELECT e.name, s.total FROM employees e JOIN ( SELECT employee_id, SUM(amount) AS total FROM sales GROUP BY employee_id ) AS s ON e.id = s.employee_id;Rewrite as a CTE for readability. If the subquery is complex, a Common Table Expression (available since MySQL 8.0) can make the intent clearer and avoids the inline alias entirely at the use site:
WITH dept_totals AS ( SELECT department AS dept, SUM(salary) AS total FROM employees GROUP BY department ) SELECT dept, total FROM dept_totals;Check nested subqueries at every level. When subqueries are nested, each level that appears in a FROM or JOIN position needs an alias:
-- Both the inner and outer derived tables need aliases SELECT outer_q.dept, outer_q.avg_total FROM ( SELECT dept, AVG(total) AS avg_total FROM ( SELECT department AS dept, SUM(salary) AS total FROM employees GROUP BY department ) AS inner_agg GROUP BY dept ) AS outer_q;Audit query-building code. If the query is generated dynamically, search for places where a subquery string is concatenated into a
FROMorJOINclause without appending an alias. A simple check is to ensure every)that closes a subquery in those positions is followed byAS.
Additional Information
- The SQLSTATE code is
42000(Syntax Error or Access Rule Violation), which places this firmly in the parse/syntax error category — not a runtime or permission issue. - This rule applies to all MySQL versions, including MySQL 5.5, 5.6, 5.7, and 8.x. There is no strict mode flag that affects it.
- MariaDB enforces the same rule and raises the same error code and message.
- PostgreSQL, by contrast, issues error
42601with the message "subquery in FROM must have an alias" — the semantic requirement is the same, but the error code differs. - Aliases do not need to be unique across the entire query, but they must be unique within the same query scope to avoid ambiguous references.
- The
ASkeyword is optional syntactically —FROM (SELECT ...) twithoutASis valid — but usingASimproves readability.
Frequently Asked Questions
Why does MySQL require an alias for derived tables at all? MySQL needs to give the result set of a subquery a name so that outer parts of the query can reference its columns unambiguously. Without an alias, the optimizer and parser have no way to qualify column references back to that relation.
Does this apply to subqueries in WHERE or SELECT, or only FROM?
Only subqueries that appear in the FROM or JOIN clause (derived tables) require an alias. Scalar subqueries in SELECT or WHERE (e.g., WHERE id IN (SELECT id FROM ...)) do not.
I added an alias but still get an error — what else could be wrong?
Check that the alias is placed immediately after the closing ) of the subquery, before any ON, WHERE, or GROUP BY clause. Also verify there are no nested subqueries at inner levels that are also missing aliases.
Can I use the same alias name for two subqueries in the same query?
Not in the same scope. If two subqueries appear at the same nesting level in a FROM clause, they must have distinct aliases. You can reuse a name at different nesting levels, but it is best avoided for clarity.