ERROR 3065 (HY000): Expression #N of ORDER BY clause is not in SELECT list, references column '<table>.<column>' which is not in SELECT list; this is incompatible with DISTINCT is raised when a query uses DISTINCT (or certain aggregation contexts) and the ORDER BY clause references a column or expression that is not present in the SELECT list. The error symbol is ER_ORDER_WITH_PROC.
Impact
The query is rejected outright — no rows are returned and execution stops immediately. This commonly surfaces when DISTINCT is combined with an ORDER BY on a column that was intentionally excluded from the select list, or when a query is migrated from a permissive MySQL 5.x environment to a stricter MySQL 5.7+ or 8.x environment where ONLY_FULL_GROUP_BY is enabled by default.
Applications using ORMs such as Hibernate, ActiveRecord, or SQLAlchemy may encounter this error at runtime when the ORM generates a DISTINCT query with an ORDER BY on a joined column — a pattern common in has_many associations or eager loading with sorting.
Common Causes
DISTINCTwithORDER BYon an excluded column. The SQL standard requires that whenDISTINCTis used, every column inORDER BYmust also appear in theSELECTlist, because the sort must be applied to the deduplicated result set.-- Fails: last_login is not in the SELECT list SELECT DISTINCT user_id, email FROM users ORDER BY last_login DESC;GROUP BYquery underONLY_FULL_GROUP_BYwith a non-aggregatedORDER BYexpression. In MySQL 5.7+ theONLY_FULL_GROUP_BYSQL mode is enabled by default. AGROUP BYquery whoseORDER BYreferences a non-aggregated column not functionally dependent on theGROUP BYkey triggers a related rejection.-- Fails under ONLY_FULL_GROUP_BY: last_login is neither aggregated nor in GROUP BY SELECT department_id, COUNT(*) AS cnt FROM employees GROUP BY department_id ORDER BY last_login;Window functions with a derived column not aliased in SELECT. Queries that use
OVER()clauses and then attempt to order by the underlying partition column rather than the window function result can hit this restriction in certain MySQL 8 contexts.ORM-generated queries with implicit sorting on a join column. ActiveRecord's
order(), Django'sorder_by(), and similar ORM methods append raw column references toORDER BY. When the ORM also addsDISTINCT(e.g., to prevent duplicate rows from a join), the generated SQL frequently violates this constraint.
Troubleshooting and Resolution Steps
Identify the offending column. The error message includes the expression number and the fully-qualified column name. Use that to locate the column in your
ORDER BYclause.Add the column to the
SELECTlist. The most straightforward fix is to include theORDER BYcolumn in the projection:-- Fixed: last_login is now in the SELECT list SELECT DISTINCT user_id, email, last_login FROM users ORDER BY last_login DESC;Remove
DISTINCTif it is not required. If deduplication is not needed, dropDISTINCTand the restriction no longer applies:SELECT user_id, email FROM users ORDER BY last_login DESC;Replace
DISTINCTwithGROUP BYand aggregate the sort column. When you need deduplication but cannot add the column to the select list, restructure usingGROUP BY:SELECT user_id, email, MAX(last_login) AS last_login FROM users GROUP BY user_id, email ORDER BY last_login DESC;For ORM-generated queries, use a subquery or CTE. Wrap the sorted query in a subquery that exposes the sort column, then project only the columns you need from the outer query:
SELECT user_id, email FROM ( SELECT user_id, email, last_login FROM users ORDER BY last_login DESC ) AS sorted_users;Check the active SQL mode if you have recently migrated from MySQL 5.6 or are running on a shared host:
SELECT @@sql_mode;If
ONLY_FULL_GROUP_BYis present and you need to relax it for a legacy application, you can remove it for the session (prefer fixing the query instead):SET SESSION sql_mode = (SELECT REPLACE(@@sql_mode, 'ONLY_FULL_GROUP_BY,', ''));
Additional Information
- Related error codes: Error 1055 (
ER_WRONG_FIELD_WITH_GROUP) is the companion error forGROUP BYviolations underONLY_FULL_GROUP_BY; Error 3065 specifically targets theDISTINCT+ORDER BYmismatch and certain procedure contexts. - MySQL version differences: MySQL 5.6 and earlier silently accepted
DISTINCTqueries with non-selectedORDER BYcolumns, producing indeterminate sort behaviour. MySQL 5.7 introduced stricter enforcement. MySQL 8.0 continues this behaviour. ONLY_FULL_GROUP_BYand error 3065: Although error 3065 is most commonly encountered withDISTINCT,ONLY_FULL_GROUP_BYtightens related constraints onGROUP BYqueries and may cause similar rejections surfaced under the same error code in some MySQL 8 builds.- ORM workarounds: In ActiveRecord (Rails), use
unscope(:order)before applyingdistinctor add the sort column viaselect("..., last_login"). In Django, ensurevalues()includes every field referenced byorder_by()whendistinct()is also applied.
Frequently Asked Questions
Why did this query work in MySQL 5.6 but fail in MySQL 5.7+?
MySQL 5.6 allowed ORDER BY on columns not in the SELECT list even with DISTINCT, simply ignoring the ambiguity. MySQL 5.7 enforced the SQL standard more strictly and added ONLY_FULL_GROUP_BY to the default SQL mode, causing previously accepted queries to be rejected. Fixing the query rather than downgrading the SQL mode is strongly recommended.
Can I just disable the SQL mode to get rid of this error?
Removing ONLY_FULL_GROUP_BY (or other strict modes) from @@sql_mode will suppress some related errors, but error 3065 for DISTINCT + non-selected ORDER BY is enforced regardless of SQL mode in MySQL 5.7+. The correct fix is to align the SELECT list with the ORDER BY clause.
Does this error affect INSERT ... SELECT or CREATE TABLE ... SELECT statements?
Yes. If the inner SELECT uses DISTINCT and the ORDER BY references a column not in the select list, MySQL will raise error 3065 during execution of the INSERT or CREATE TABLE statement.
My ORM generates the query automatically — how do I fix it without writing raw SQL?
In most ORMs you can either: (a) add the sort column to the select projection explicitly, (b) use a subquery/CTE to isolate the sort from the outer distinct projection, or (c) post-process in application code if the result set is small enough. Consult your ORM documentation for select_extra, annotate, or raw query escape hatches.