error after migration from oracle 11g to 19c - sql

could anyone explain how the below select works:
select A.B.Column1 Col1
FROM TableA A LEFT JOIN TableB B
ON B.id=A.id;
What does A.B.Column1 mean? After migration from oracle 11g to 19c my package throws an error:
PL/SQL: ORA-00904: "A"."B"."Col1":
invalid identifier

It shouldn't have worked in 11g either, but ANSI syntax sometimes has issues - particularly in older versions - and you happened to hit a confusing, but fairly benign one.
In this case the parser/optimiser is apparently ignoring what could be, but isn't, a reference to the table's schema. That seems to be happening during the internal translation of the ANSI syntax to native Oracle syntax. It doesn't matter what that first part is; you've shown A matching another table's alias, but that's a coincidence; both of these work, at least in 11.2.0.2, even though Z is never mentioned anywhere else:
select A.B.Column1 Col1
FROM TableA A LEFT JOIN TableB B
ON B.id=A.id;
select Z.B.Column1 Col1
FROM TableA A LEFT JOIN TableB B
ON B.id=A.id;
I've said it's an ANSI issue because (a) it errors with an inner join as you mentioned, and (b) it also errors with old-fashioned outer-join syntax:
select A.B.Column1 Col1
FROM TableA A, TableB B
WHERE B.id = A.id (+);
ORA-00904: "A"."B"."COLUMN1": invalid identifier
SQL Fiddle demo
There isn't much point worrying about how it worked before, or (for example) raising a service request against such an old version. It's a bug in your old version of Oracle, and it's fixed now. It shouldn't have worked, and since it - correctly - doesn't work in 19c, you have to fix it, by removing the stray A..

The SQL is invalid.
Knowing this there are only 2 possibilities:
11g likewise raised an error; or
11g has a "more relaxed" error tolerance than 19c and has made an assumption as to whether A or B and applied the selection in your output.
Either way, given that it is your package, the solution should be fairly trivial:
If you know which table you are expecting the result to be from then remove the incorrect table's reference from the alias
if A has "Column1" and B doesn't then remove "B." from the alias
if B has "Column1" and A doesn't then remove "A." from the alias
If both A and B have "Column1" then find an 11g database an create a
dummy query where A.id = B.id and A.Column1 differs in value from
B.Column1. Then run the query and if the result is A.Column1 value
then remove "B." from the alias but if the result is B.Column1,
remove "A." from the alias.
if you are trying to implement the logic "if B.Column1 is null then return the value of A.Column1 otherwise return the value of B.Column1", then correct your SQL to read something like:
select case
when B.Column1 is null then
A.Column1
else
B.Column1
end as Col1
from TableA A left join TableB B
on B.id = A.id;

Related

Oracle SQL Language Reference Merge/Subquery Documentation Error?

When using the merge::= MERGE INTO ... USING subquery t_alias it appears one must enclose the subquery in parenthesis like MERGE INTO ... USING (subquery) t_alias. However, the Oracle SQL Language Reference documentation's syntax diagram for subquery::= appears to show that an optional path (via query_block) does not require parenthesis. That is the documentation appears to allow both versions.
For example:
This following is invalid, but allowable per the documentation.
MERGE INTO tblA A
USING SELECT col FROM tblB B -- ORA-00903 invalid table name and "SELECT" is highlighted.
ON (A.id = B.id)
...
The following is valid (and also allowable per the documentation).
MERGE INTO tblA A
USING (SELECT col FROM tblB) B
ON (A.id = B.id)
...
According to How to Read Syntax Diagrams
If the syntax diagram has more than one path, then you can choose any path.
Is there an Oracle SQL Language Reference documentation error?
Thanks in advance.
In MERGE query, the operand used after USING clause is not exactly a sub query. It actually defines a table. For example: if you want to update a table from the values from another table.
MERGE INTO tblA A
USING tblB B
ON (A.id = B.id)
...
In case tblB has very huge amount of data and you want to optimise the
perfomance, you can use a query to fetch required columns from the table.
MERGE INTO tblA A
USING (SELECT col1, col2, col3 FROM tblB) B -- here we are not using complete table,
instead we are using only required columns from the table
ON (A.id = B.id)
...
Merge is also similar to join, below is the better way of understanding
select * from tblA A
inner join tblB B
ON (A.id = B.id);
or
select * from tblA A
inner join (SELECT col1, col2, col3 FROM tblB) B
ON (A.id = B.id);
The reason you get invalid table name is, when you do not enclose the select statement in brackets, Oracle will not know the aliases of the table you are using. So always enclose a bracket when you have a certain conditions in the query.

Update using Inner Join throwing syntax error

I would like to update columns in Table A based on values in Table B. Using below format, but getting syntax error.
update TableA
set
TableA.MOdule_id =TableB.MOdule_id
from TableA
inner join
TableB
on TableA.end_Slot_id =TableB.Slot_Id
where TableA.Slot_Id = 'AAA';
It would be great help, if anyone can help on this.
A quick search for "informix sql update" returns two reference manual pages that describe the syntax for the UPDATE command. Neither one indicates support for the nonstandard FROM clause.
Standard SQL uses a correlated subquery for the purpose. Your query should look something like
update TableA
set MOdule_id =
(select TableB.MOdule_id
from TableB
on TableA.end_Slot_id = Slot_Id)
where Slot_Id = 'AAA'
and exists (
select 1
from TableB
on TableA.end_Slot_id = Slot_Id
and TableA.Slot_Id = 'AAA'
);
The EXISTS clause ensures that only rows that exist in B are applied to A. Without it, any missing rows would be updated to NULL.

Double/Random alias name in select clause on Oracle 11g does not throw invalid identifier exception

Yesterday I stumbled upon some strange behavior on a customers Oracle 10g instance. Some procedure I wrote gave me an invalid identifier exception but was running fine on my Oracle 11g instances.
The relevant query was something like the following:
select b.b.v_col_b
from tbla a
left join tblb b on a.pk_col_a = b.fk_a;
Pleas note the b.b.v_col_b part of the query. Changing from left join to inner join did finally raise a ORA-00904: "B"."B"."V_COL_B": invalid identifier exception, but:
Isn't this a syntax error?
Can somebody explain this behaviour?
A working demo can be found on sqlfiddle
Edit: Added the table definition:
create table tbla (
pk_col_a int primary key,
v_col_a varchar2(50));
create table tblb (
pk_col_b int primary key,
fk_a int,
v_col_b varchar2(50));
Edit2: As #LalitKumarB's mentioned this only seems to happen on Oracle 11g
Congratulations, you have found a bug :)
In that particular case you can write whatever you want when selecting any of the tblb columns:
select helloworld.b.v_col_b, mghjfghj.b.fk_a, asdasdas.b.pk_col_b
from tbla a
left join tblb b on a.pk_col_a = b.fk_a;
You can even do it with a right join:
select helloworld.b.v_col_b, mghjfghj.b.fk_a, asdasdas.b.pk_col_b
from tblb b
right join tbla a on a.pk_col_a = b.fk_a;
It won't work with the Oracle join syntax ( (+) notation ) though.
It is not an expected behaviour and, as Lalit noted in the comments, is fixed in 12C. You can file a bug request wit Oracle Support if you want. Maybe there is already a patch for it.
ORA-00904: "B"."B"."V_COL_B": invalid identifier
In SQL the qualified identifier X.Y.Z relates at a scheme X, table Y, and column Z. Whereas a simple Y.Z means table Y, column Z.
And then calling X.Y.Z an identifier might be misleading too, but not too irregular in computer science.
On the error behavior you did experience I cannot tell much.

SQL JOIN that uses OR in the ON statement

I’m running a SQL query on Google BigQuery and want to do this kind of SQL command:
SELECT ... FROM A JOIN B
ON A.col1=B.col1 AND (A.col2=B.col2 OR A.col3=B.col3)
This fails though with the error:
Error: ON clause must be AND of = comparisons of one field name from each table, with all field names prefixed with table name.
Is there a way to rewrite the SQL to get this kind of functionality?
Turns out this works, which is equivalent to a UNION ALL statement in Google BigQuery. Not sure how to do it if you just want a UNION, since DISTINCT is actually not supported in BigQuery. Luckily it's enough for me as is.
SELECT ... FROM
(SELECT ... FROM A JOIN B ON A.col1=B.col1 AND A.col2=B.col2),
(SELECT ... FROM A JOIN B ON A.col1=B.col1 AND A.col3=B.col3)
This should work:
SELECT ... FROM A CROSS JOIN B
WHERE A.col1=B.col1 AND (A.col2=B.col2 OR A.col3=B.col3)

Oracle 22 Joins or over is not allowed in a select statement ? ORA-01445

ORA-01445: cannot select ROWID from, or sample, a join view without a
key-preserved table
I have a long select statement on ORACLE 10g.
According to this error statement, I have seen some answers on google. One of the answer is saying that ;
* limit on number of tables in join I 've run across an unusual bug
(4204878/ 3765373/ 3004824) on Oracle 9.2.0.5. When more than 22 ANSII
joins are done in a select statement an ORA-01445 occurs. According to
Support "1- One so
I count the number of joins inside the whole select block; is 23 (after select and after where clause).
The SP which has this "selec"t statement was working perfectly until I added this new join after where clause...
For short, I ve tested by disabling one of existing join and enabled my newly added join and SP worked.
What do you think are there really any limit ?
** I can't give you the web site addess since it is always found smearing by the users of StackOverflow..
I've run into these bugs a couple of times. It happened a lot in 9i with ANSI joins and i've found it happens less frequently in 10g.
One workaround is to rewrite the join to use the "old" join synthax, specifically outer joins as APC pointed out:
SELECT *
FROM a, b
WHERE a.a_id = b.a_id (+)
I've solved that issue by just selecting the columns that I used on query.
From this:
select a.column1, b.column3
from a
join b on b.column2 = a.column2
To this:
select a.column1, b.column3
from (select column1, column2 from a) a
join (select column2, column3 from b) b on b.column2 = a.column2