Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Is order in a subquery guaranteed to be preserved?

I am wondering in particular about PostgreSQL. Given the following contrived example:

SELECT name FROM
  (SELECT name FROM people WHERE age >= 18 ORDER BY age DESC) p
LIMIT 10

Are the names returned from the outer query guaranteed to be be in the order they were for the inner query?

like image 738
knpwrs Avatar asked Apr 27 '13 05:04

knpwrs


People also ask

Does ORDER BY subquery work?

An ORDER BY command cannot be used in a subquery, although the main query can use an ORDER BY. The GROUP BY command can be used to perform the same function as the ORDER BY in a subquery.

Why is ORDER BY not allowed in subquery?

No ORDER BY is valid in a subquery when you are interested in a subset of the overall data, hence you always need a TOP (SQL Server). There's no point having an ORDER BY without TOP in a subquery because the overall ordering of the results is handled by the outer query.

Why is ORDER BY in a from subquery ignored?

A "table" (and subquery in the FROM clause too) is - according to the SQL standard - an unordered set of rows. Rows in a table (or in a subquery in the FROM clause) do not come in any specific order. That's why the optimizer can ignore the ORDER BY clause that you have specified.

What are the limitations of subquery?

Subqueries cannot manipulate their results internally, that is, a subquery cannot include the order by clause, the compute clause, or the into keyword. Correlated (repeating) subqueries are not allowed in the select clause of an updatable cursor defined by declare cursor. There is a limit of 50 nesting levels.


2 Answers

No, put the order by in the outer query:

SELECT name FROM
  (SELECT name, age FROM people WHERE age >= 18) p
ORDER BY p.age DESC
LIMIT 10

The inner (sub) query returns a result-set. If you put the order by there, then the intermediate result-set passed from the inner (sub) query, to the outer query, is guaranteed to be ordered the way you designate, but without an order by in the outer query, the result-set generated by processing that inner query result-set, is not guaranteed to be sorted in any way.

like image 115
Charles Bretana Avatar answered Nov 14 '22 23:11

Charles Bretana


For simple cases, @Charles query is most efficient.

More generally, you can use the window function row_number() to carry any order you like to the main query, including:

  • order by columns not in the SELECT list of the subquery and thus not reproducible
  • arbitrary ordering of peers according to ORDER BY criteria. Postgres will reuse the same arbitrary order in the window function within the subquery. (But not truly random order from random() for instance!)
    If you don't want to preserve arbitrary sort order of peers from the subquery, use rank() instead.

This may also be generally superior with complex queries or multiple query layers:

SELECT name
FROM  (
   SELECT name, row_number OVER (ORDER BY <same order by criteria>) AS rn
   FROM   people
   WHERE  age >= 18
   ORDER  BY <any order by criteria>
   ) p
ORDER  BY p.rn
LIMIT  10;
like image 27
Erwin Brandstetter Avatar answered Nov 14 '22 22:11

Erwin Brandstetter