How to Fix MySQL Error 1066: Not Unique Table/Alias in Query

ERROR 1066 (42000): Not unique table/alias: '<name>' is raised when a query's FROM clause (or JOIN chain) references the same table name or alias more than once and MySQL cannot distinguish between the two references. The error symbol is ER_NONUNIQ_TABLE.

Impact

The query is rejected immediately — no rows are read or modified. Because MySQL cannot determine which instance of the table a column reference belongs to, it refuses to parse the statement rather than return ambiguous results. The error appears at parse time, so it never touches any transaction state and there is no rollback needed.

Developers most often hit this when writing self-joins, copying a JOIN clause by mistake, or when an ORM generates a query that joins the same table twice for two different associations. Frameworks like Hibernate, ActiveRecord, or SQLAlchemy can produce duplicate table references when eager-loading multiple relations that share an intermediate table, so the error may surface as a runtime exception in application logs rather than during local development.

Common Causes

  1. Self-join without aliases — Joining a table to itself without assigning distinct aliases to each reference. MySQL requires unique identifiers for every table instance in a FROM or JOIN clause.
  2. Duplicate table in FROM clause — Listing the same table twice in a comma-separated FROM clause or adding it both explicitly and via a JOIN.
  3. Subquery alias collision — Using the same alias for a derived table or subquery as for a base table already referenced in the outer query.
  4. ORM or query-builder generating duplicate joins — Two relationships defined on the same model both resolve to the same table, and the query builder adds it twice without generating unique aliases.
  5. Copy-paste error in complex queries — Duplicating a LEFT JOIN block while editing a multi-join query and forgetting to remove or rename the copy.

Troubleshooting and Resolution Steps

  1. Identify the duplicate name in the error message. MySQL tells you the exact name or alias that is duplicated. Locate every occurrence of that identifier in your FROM and JOIN clauses.

  2. Add distinct aliases to a self-join. Every instance of the table must have a unique alias:

    -- Broken: same table referenced twice with no alias
    SELECT a.id, b.manager_id
    FROM employees, employees
    WHERE employees.manager_id = employees.id;
    
    -- Fixed: assign a unique alias to each instance
    SELECT e.id, m.id AS manager_id
    FROM employees AS e
    JOIN employees AS m ON e.manager_id = m.id;
    
  3. Remove the accidental duplicate join. If the same table appears more than once but you only need it once, delete the extra JOIN or FROM entry:

    -- Broken: orders joined twice
    SELECT o.id, c.name
    FROM orders o
    JOIN customers c ON o.customer_id = c.id
    JOIN orders o ON o.status = 'pending';   -- duplicate
    
    -- Fixed: apply the extra condition to the existing join or a WHERE clause
    SELECT o.id, c.name
    FROM orders o
    JOIN customers c ON o.customer_id = c.id
    WHERE o.status = 'pending';
    
  4. Alias subqueries so they do not collide with base tables. A derived table alias must differ from every other table alias in the same query scope:

    -- Broken: derived table shares the name 'orders'
    SELECT *
    FROM orders
    JOIN (SELECT customer_id FROM orders WHERE total > 100) AS orders
      ON orders.customer_id = orders.customer_id;
    
    -- Fixed: use a distinct alias for the subquery
    SELECT o.*
    FROM orders o
    JOIN (SELECT customer_id FROM orders WHERE total > 100) AS big_orders
      ON o.customer_id = big_orders.customer_id;
    
  5. Inspect ORM-generated SQL. Enable query logging or use your framework's debug/explain mode to see the raw SQL. For example, in MySQL you can enable the general log temporarily:

    SET GLOBAL general_log = 'ON';
    SET GLOBAL general_log_file = '/tmp/mysql_general.log';
    

    Once you find the duplicate join in the generated SQL, fix it at the ORM layer by specifying explicit join conditions or using a single association instead of two that resolve to the same table.

Additional Information

  • The SQLSTATE code is 42000 (Syntax Error or Access Rule Violation), which means the error is treated as a syntax/parse problem, not a data error.
  • Error 1066 is purely a query-construction issue and does not depend on MySQL's sql_mode settings — it is raised in all modes.
  • The error applies equally to SELECT, UPDATE with multi-table syntax, and DELETE with multi-table syntax. Multi-table UPDATE and DELETE statements are particularly prone to duplicate table references because the updated table often appears in both the target list and the FROM/JOIN clause — MySQL handles that specific pattern, but any other duplication still raises 1066.
  • Related error: ERROR 1052 (23000): Column '<col>' in <clause> is ambiguous — this is a different error raised when column names are ambiguous across multiple tables, whereas 1066 is about the table/alias names themselves being non-unique.

Frequently Asked Questions

Why does MySQL require unique table aliases at all? MySQL's query planner needs an unambiguous way to refer to each row source in a query. If two references share the same name, column references like tablename.column become undefined because MySQL cannot know which instance you mean. Requiring unique names at parse time prevents silently wrong results.

Can I join the same table more than once in a single query? Yes, but every instance must have a distinct alias. This is standard SQL and is commonly used for self-joins, or when joining a lookup/reference table for two different foreign keys in the same row. Just ensure each JOIN clause uses a different alias (AS a, AS b, etc.).

The error appears in my application but I cannot see the SQL. How do I find it? Enable the MySQL general query log (SET GLOBAL general_log = 'ON') or, in a development environment, configure your ORM to log SQL statements. In Django use django.db.backends logging; in Rails set config.log_level = :debug; in Spring Boot set logging.level.org.hibernate.SQL=DEBUG. The raw SQL will contain the duplicate table name.

Does this error occur with CTEs (Common Table Expressions)? A CTE name must also be unique within the WITH clause, but CTEs use a different error path. If you reference the same CTE name twice in the main query you will still get error 1066, because the CTE name acts as a table alias in the main FROM/JOIN scope.

Subscribe to the Pulse Newsletter

Get early access to new Pulse features, insightful blogs & exclusive events , webinars, and workshops.

We use cookies to provide an optimized user experience and understand our traffic. To learn more, read our use of cookies; otherwise, please choose 'Accept Cookies' to continue using our website.