The logical order of standard ISO SQL clauses for the SQL SELECT statement is :
- FROM
- WHERE
- GROUP BY
- HAVING
- WINDOW
- SELECT
- ORDER BY
All other keyword are subclauses (JOIN / ON, DISTINCT, OFFSET / FETCH...) or operators (IN, BETWEEN, EXISTS...) depending on SQL clauses.
Contrary to what @Laurenz_Albe says, the AS keyword introduces an alias, that is to say a new name, for a column or a table, which can be used in the clauses located after it, in the logical order. Thus an AS defining an alias for a column of the SELECT clause can only be used in the ORDER BY clause and in no case in other of the following elements of the SELECT clause.
So :
SELECT COL1 AS X, X + 1
Must throw an exception.
On the other hand, a table alias can be used in any other clause, including following the sequence of elements of the FROM clause in which it is defined.
So :
SELECT *
FROM Tab1 AS T
JOIN Tab2 AS U
ON T.id = U.id
...is correct
The query givent by @Laurenz_Albe :
SELECT t.c AS x
FROM (VALUES (1), (2)) AS t(c)
WHERE EXISTS (SELECT WHERE t.c = 1);
...is syntaxically false in SQL and cannott be accepted by any RDBMS, except PostGreSQL. Because the inner SELECT clause must have almost an element. A correct query can be :
SELECT t.c AS x
FROM (VALUES (1), (2)) AS t(c)
WHERE EXISTS (SELECT * WHERE t.c = 1);
Avoid to write such stupid query that is syntaxically innaceptable...
By the way,
kewords ON and PARTITIONNED depends of a JOIN, that depends of the FROM clause, like LATERAL { CROSS |OUTER } APPLY.
keyword DISTINCT wich is an operator depend of the FROM clause and must preceed any element of this clause
keyword LIMIT is not a part of the ISO SQL standard.
Keyword OFFSET depend of the ORDER BY clause and FETCH depend of OFFSET.
But do not make confusion between the logical order and the physical treatment of the query. A query is just a sentence translated into a mathematical formulae of relational algebra and this formulae can be:
As a basic example of simplification :
SELECT *
FROM T
WHERE Col1 + 3 = 5
would be rewrited as :
SELECT *
FROM T
WHERE Col1 = 2
A more sophisticated simplification by rewriting can be :
SELECT COUNT(*), PrimaryKeyCol, Col2, Col3, Col4, Col5
FROM T
GROUP BY PrimaryKeyCol, Col2, Col3, Col4, Col5
...that would be rewrited as ::
SELECT COUNT(*), PrimaryKeyCol, Col2, Col3, Col4, Col5
FROM T
GROUP BY PrimaryKeyCol
Depending of the level of "intelligence" of the optimizer (stupidly called planer in PostGreSQL)...