find group by clause error programmatically - sql

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.

Related

What is SQL's Keyword order? (Postgresql)

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.

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?

Reference a renamed variable with the same name in the source table

I'm trying to reference the new variable DATE_YEAR instead the original DATE_YEAR that I have in my Teradata database TEST.
How can i get it?
I found nothing in Teradata documentation.
SELECT DATE_YEAR+1 AS DATE_YEAR, COUNT(1)
FROM TEST
WHERE DATE_YEAR = 2016 GROUP BY 1;
Based on Standard SQL the columns in the SELECT-list are created after FROM/WHERE/GROUP BY/HAVING/OLAP, but before ORDER BY, so you can use an alias only in ORDER BY.
Due to historical reasons Teradata allows reusage of an alias in any place, this is very convenient as you don't have to cut&paste or use nested SELECTs. But there are some scoping rules, only when a column name is not found it's looked up in the alias-list. So the rough rule of thumb is: Never assign an alias which matches an existing column name and then you can easily use it in any place:
SELECT DATE_YEAR+1 AS DATE_YR, COUNT(1)
FROM TEST
WHERE DATE_YR = 2016 GROUP BY 1;
Wrap it up in a derived table:
select DATE_YEAR_ADJUSTED, count(*)
from
(
SELECT DATE_YEAR+1 AS DATE_YEAR_ADJUSTED
FROM TEST
) as dt
WHERE DATE_YEAR_ADJUSTED = 2016
GROUP BY DATE_YEAR_ADJUSTED
That GROUP BY doesn't make much sense... Only one year anyway.
PS. I don't know Teradata, but I hope this works. ANSI SQL.

Oracle SQL Error: ORA-00923: From Keyword not found where expected

When I use the following sql command for Oracle:
SELECT CATEGORY,ANTIGENNAME,LATINCOMPOSITION,HYCORCODE,FDACLEARANCE, LISTAGG(ORCHARDCODE, ';')
WITHIN GROUP (ORDER BY ORCHARDCODE) as code
from tablename
group by HYCORCODE
I'm seem to be getting a ORA-00923 error:
ORA-00923: FROM keyword not found where expected
What could be causing the error to show up?
LISTAGG is not available in your version of Oracle. Check your version with this statement:
select * from v$version;
LISTAGG is only available on versions >= 11.2.x
From "Oracle Database 11g Release 2 (11.2) New Features in Data Warehousing":
Analytic Functions
New SQL analytic functions have been introduced that enable you to list (or concatenate) measure values within a group (LISTAGG).
code is not a reserved word, so I don't think it needs to be quoted (see here).
However, you have an aggregation function, so you need the correct columns in the group by:
SELECT CATEGORY, ANTIGENNAME, LATINCOMPOSITION, HYCORCODE, FDACLEARANCE,
LISTAGG(ORCHARDCODE, ';') WITHIN GROUP (ORDER BY ORCHARDCODE) as code
from tablename
group by CATEGORY, ANTIGENNAME, LATINCOMPOSITION, HYCORCODE, FDACLEARANCE;
This definitely fixes a problem with your query. I'm not sure if it will fix your particular error. When I leave out columns from the group by, I get "ORA-00979 (not a GROUP BY expression)."

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?