What is SQL's Keyword order? (Postgresql) - sql

Depending on where you put SELECT, FROM, WHERE, etc, I have run into syntax errors. What is the proper order to write queries and code? An example below:
//No error
SELECT count(*)
FROM us_counties_pop_est_2019
WHERE births_2019 - deaths_2019 <=0;
vs
//Syntax error
SELECT count(*)
WHERE births_2019 - deaths_2019 <=0
FROM us_counties_pop_est_2019;

The main clauses of a SELECT statement in PostgreSQL are written in the following order:
[WITH]
SELECT
FROM
JOIN
WHERE
GROUP BY
HAVING
WINDOW
ORDER BY
OFFSET
LIMIT
If the query includes CTEs, then the WITH clause comes before the other ones.

Related

Query working in MySQL but trowing error in Oracle can someone please explain. and tell me how to rewrite this same query in oracle to avoid error [duplicate]

I have a query
SELECT COUNT(*) AS "CNT",
imei
FROM devices
which executes just fine. I want to further restrict the query with a WHERE statement. The (humanly) logical next step is to modify the query followingly:
SELECT COUNT(*) AS "CNT",
imei
FROM devices
WHERE CNT > 1
However, this results in a error message ORA-00904: "CNT": invalid identifier. For some reason, wrapping the query in another query produces the desired result:
SELECT *
FROM (SELECT COUNT(*) AS "CNT",
imei
FROM devices
GROUP BY imei)
WHERE CNT > 1
Why does Oracle not recognize the alias "CNT" in the second query?
Because the documentation says it won't:
Specify an alias for the column
expression. Oracle Database will use
this alias in the column heading of
the result set. The AS keyword is
optional. The alias effectively
renames the select list item for the
duration of the query. The alias can
be used in the order_by_clause but not
other clauses in the query.
However, when you have an inner select, that is like creating an inline view where the column aliases take effect, so you are able to use that in the outer level.
The simple answer is that the AS clause defines what the column will be called in the result, which is a different scope than the query itself.
In your example, using the HAVING clause would work best:
SELECT COUNT(*) AS "CNT",
imei
FROM devices
GROUP BY imei
HAVING COUNT(*) > 1
To summarize, this little gem explains:
10 Easy Steps to a Complete Understanding of SQL
A common source of confusion is the simple fact that SQL syntax
elements are not ordered in the way they are executed. The lexical
ordering is:
SELECT [ DISTINCT ]
FROM
WHERE
GROUP BY
HAVING
UNION
ORDER BY
For simplicity, not all SQL clauses are listed. This lexical ordering
differs fundamentally from the logical order, i.e. from the order of
execution:
FROM
WHERE
GROUP BY
HAVING
SELECT
DISTINCT
UNION
ORDER BY
As a consequence, anything that you label using "AS" will only be available once the WHERE, HAVING and GROUP BY have already been performed.
I would imagine because the alias is not assigned to the result column until after the WHERE clause has been processed and the data generated. Is Oracle different from other DBMSs in this behaviour?

find group by clause error programmatically

We are going to update our database from 10g to 12c. Before doing so we need to revisit our SQLs, and as a part of this we need to check the following behavior of GROUP BY
case 1:
SELECT abcd_pk,
COUNT(abcd_code),
ABCD_COUNT
FROM
(SELECT abcd_pk,
abcd_code,
(SELECT COUNT(abcd_code) FROM ABCD_TABLE
) "ABCD_COUNT"
FROM ABCD_TABLE
)
GROUP BY abcd_pk, ABCD_COUNT ;
WORKS IN 10G
WORKS IN 12C
case 2:
SELECT abcd_pk,
COUNT(abcd_code),
ABCD_COUNT
FROM
(SELECT abcd_pk,
abcd_code,
(SELECT COUNT(abcd_code) FROM ABCD_TABLE
) "ABCD_COUNT"
FROM ABCD_TABLE
)
GROUP BY abcd_pk ;
WORKS IN 10G
DOES NOT WORK IN 12C (ORA-00979: not a GROUP BY expression 00979. 00000 - "not a GROUP BY expression")
Our code may contains case2 like SQL which is not appropriate. So we need to identify those SQLs. I already prepared a list of SQLs contains GROUP BY used in our project (.java files/procedure/function/views etc.).
Requirement is find the problem in GROUP BY using the following process:
Check the SQLs in the list one by one.
Find an alternate way to check the list of SQLs programmatically.
Option 1 requires massive work load, effort and time, but I think option 2 is not possible.
Is there any suggestion how to proceed?
One possible workaround which might work would be to place the count subquery into an aggregate function, e.g. AVG():
SELECT abcd_pk,
COUNT(abcd_code),
AVG(ABCD_COUNT) -- use an aggregate to not offend Oracle
FROM
(
SELECT abcd_pk,
abcd_code,
(SELECT COUNT(abcd_code) FROM ABCD_TABLE) "ABCD_COUNT"
FROM ABCD_TABLE
)
GROUP BY abcd_pk;
If this fixes the problem, then it means that Oracle's treatment of subqueries resulting in constants has changed between 10G and 12C.

Using the DISTINCT keyword causes this error: not a SELECTed expression

I have a query that looks something like this:
SELECT DISTINCT share.rooms
FROM Shares share
left join share.rooms.buildingAdditions.buildings.buildingInfoses as bi
... //where clause omitted
ORDER BY share.rooms.floors.floorOrder, share.rooms.roomNumber,
share.rooms.firstEffectiveAt, share.shareNumber, share.sharePercent
Which results in the following exception:
Caused by: org.hibernate.exception.SQLGrammarException: ORA-01791: not a SELECTed expression
If I remove the DISTINCT keyword, the query runs without issue. If I remove the order by clause, the query runs without issue. Unfortunately, I can't seem to get the ordered result set without duplicates.
You are trying to order your result with columns that are not being calculated. This wouldn't be a problem if you didn't have the DISTINCT there, but since your query is basically grouping only by share.rooms column, how can it order that result set with other columns that can have multiple values for the same share.rooms one?
This post is a little old but one thing I did to get around this error is wrap the query and just apply the order by on the outside like so.
SELECT COL
FROM (
SELECT DISTINCT COL, ORDER_BY_COL
FROM TABLE
// ADD JOINS, WHERE CLAUSES, ETC.
)
ORDER BY ORDER_BY_COL;
Hope this helps :)
When using DISTINCT in a query that has an ORDER BY you must select all the columns you've used in the ORDER BY statement:
SELECT DISTINCT share.rooms.floors.floorOrder, share.rooms.roomNumber,
share.rooms.firstEffectiveAt, share.shareNumber, share.sharePercent
...
ORDER BY share.rooms.floors.floorOrder, share.rooms.roomNumber,
share.rooms.firstEffectiveAt, share.shareNumber, share.sharePercent

SQL Server ORDER BY clause in subquery

I am facing a strange error in SQL Server and I want some explanation of it.
When I write ORDER BY in a subquery, for instance
SELECT a FROM (SELECT * FROM A ORDER BY a) T
it throws the following error
The ORDER BY clause is invalid in views, inline functions, derived
tables, subqueries, and common table expressions, unless TOP or FOR
XML is also specified.
But when I use TOP in subquery it works normally
SELECT a
FROM
(SELECT TOP 1000000 * FROM A ORDER BY a) T
So, does it mean that I can select top row count of A, instead of
SELECT a FROM (SELECT * FROM A ORDER BY a) T
In that case. what is the reason of error?
There is no much sense to sort the subquery and after that select something from it - it is not guaranteed that top-level select will be ordered, so - there is no sense to order the inner query
But if you order inner query with TOP statement - it also not guaranteed that top level select will be ordered in such a way, but it will contain only top X rows from the inner query - that is already makes sense.

Understanding Oracle aliasing - why isn't an alias not recognized in a query unless wrapped in a second query?

I have a query
SELECT COUNT(*) AS "CNT",
imei
FROM devices
which executes just fine. I want to further restrict the query with a WHERE statement. The (humanly) logical next step is to modify the query followingly:
SELECT COUNT(*) AS "CNT",
imei
FROM devices
WHERE CNT > 1
However, this results in a error message ORA-00904: "CNT": invalid identifier. For some reason, wrapping the query in another query produces the desired result:
SELECT *
FROM (SELECT COUNT(*) AS "CNT",
imei
FROM devices
GROUP BY imei)
WHERE CNT > 1
Why does Oracle not recognize the alias "CNT" in the second query?
Because the documentation says it won't:
Specify an alias for the column
expression. Oracle Database will use
this alias in the column heading of
the result set. The AS keyword is
optional. The alias effectively
renames the select list item for the
duration of the query. The alias can
be used in the order_by_clause but not
other clauses in the query.
However, when you have an inner select, that is like creating an inline view where the column aliases take effect, so you are able to use that in the outer level.
The simple answer is that the AS clause defines what the column will be called in the result, which is a different scope than the query itself.
In your example, using the HAVING clause would work best:
SELECT COUNT(*) AS "CNT",
imei
FROM devices
GROUP BY imei
HAVING COUNT(*) > 1
To summarize, this little gem explains:
10 Easy Steps to a Complete Understanding of SQL
A common source of confusion is the simple fact that SQL syntax
elements are not ordered in the way they are executed. The lexical
ordering is:
SELECT [ DISTINCT ]
FROM
WHERE
GROUP BY
HAVING
UNION
ORDER BY
For simplicity, not all SQL clauses are listed. This lexical ordering
differs fundamentally from the logical order, i.e. from the order of
execution:
FROM
WHERE
GROUP BY
HAVING
SELECT
DISTINCT
UNION
ORDER BY
As a consequence, anything that you label using "AS" will only be available once the WHERE, HAVING and GROUP BY have already been performed.
I would imagine because the alias is not assigned to the result column until after the WHERE clause has been processed and the data generated. Is Oracle different from other DBMSs in this behaviour?