I am asking this question because I am not getting an error where I expect there should be an error.
Please help me understand under what circumstances this is possible. I have a query:
select foracid,acct_name, schm_code, schm_type from tbaadm.gam where
acid in(select acid from tbaadm.iar);
This query is returning results without throwing any error. I expect invalid identifier
because the table tbaadm.iar does NOT have a field acid.
When I run:
select acid from tbaadm.iar;
I get:
ORA-00904: "ACID": invalid identifier
00904. 00000 - "%s: invalid identifier"
*Cause:
*Action:
Error at Line: 772 Column: 8
I am using sqldeveloper and oracle 10g. It is kind of Strange to me. Worth to mention though is that there is a field in tbaadm.iar that is an id and so the right Query Should be:
select foracid,acct_name, schm_code, schm_type from tbaadm.gam where
acid in(select entity_id from tbaadm.iar);
What is going on here?
A subquery that's used in an IN clause can reference columns from the outer query, because this is necessary in correlated subqueries. So your WHERE clause is equivalent to:
WHERE acid IN (SELECT tbaadm.gam.acid FROM tbaadm.iar)
An example of a correlated subquery that shows why this is necessary is:
SELECT *
FROM outer_table
WHERE somefield = (SELECT someotherfield
FROM inner_table
WHERE inner_table.id = outer_table.inner_id)
This is the more common use, where the field from the outer table is used in a WHERE clause of the subquery. But SQL isn't picky about where the field from the outer query is used. It can be used anywhere in the subquery that an expression is permitted, which includes the SELECT clause.
Related
I have to run the following UPDATE query into an Oracle database.
UPDATE Appliance
SET Appliance.IdApplianceType =
(
SELECT AT.id
FROM Appliance A INNER JOIN ApplianceType AT
ON UPPER(A.typeName) = UPPER(AT.name)
AND Appliance.id = A.id)
The objective is to find the match between records of Appliance.typeName and ApplianceType.name and set the ApplianceType.id (primary key) in the Appliance.IdApplianceType (FK ApplianceType) (Note: In a 2nd step normalize Appliance table removing Appliance.typeName column and to use IdApplianceType like relation.)
In oracle 12c(and sqlserver 2008+) it works while in version 11g doesn't work.
I report the error below
QL Error: ORA-00904: "APPLIANCE"."ID": invalid identifier
00904. 00000 - "%s: invalid identifier"
*Cause:
*Action:
Any help will be appreciated :)
Thanks
The extra join seems unnecessary. Why not just use this simpler version?
UPDATE Appliance
SET Appliance.IdApplianceType =
(SELECT AT.id
FROM ApplianceType AT
WHERE UPPER(Appliance.typeName) = UPPER(AT.name)
);
I can not figure it out what is wrong with this query:
select * from inv_srv_inst inst,
(select srvc.li_srv_cat_id from inv_li_srv_cat_srv srvc where srvc.srv_id = inst.service_id) li_srv_cat_id
where id in (37336558,37343286)
Error message:
ORA-00904: "INST"."SERVICE_ID": invalid identifier
00904. 00000 - "%s: invalid identifier"
ORA-00904: "INST"."SERVICE_ID": invalid identifier
You get this error because INV_SRV_INST is not in scope of the inline view. If you're using 12c or later you can work around this using the LATERAL keyword, which allows us to push predicates into subqueries:
select *
from inv_srv_inst inst,
lateral (select srvc.li_srv_cat_id
from inv_li_srv_cat_srv srvc
where srvc.srv_id = inst.service_id) li_srv_cat_id
where id in (37336558,37343286)
Although it must be asked, why did you choose an inline view rather than just joining the two tables?
select inst.*
,srvc.li_srv_cat_id
from inv_srv_inst inst
inner join inv_li_srv_cat_srv srvc
on srvc.srv_id = inst.service_id
where inst.id in (37336558,37343286)
Here is a demo on db<>fiddle.
Never use commas in the FROM clause.
In your case, you can express this using a lateral join or a correlated subquery -- assuming there is only one match.
select *
from inv_srv_inst inst cross join lateral
(select srvc.li_srv_cat_id
from inv_li_srv_cat_srv srvc
where srvc.srv_id = inst.service_id
) li_srv_cat_id
where inst.id in (37336558, 37343286);
Lateral joins are very handy. They are like correlated subqueries but they can return multiple columns and multiple rows.
I have written the following query
SELECT TPD.*,
FMP.*
FROM TABLE TPD
LEFT JOIN
(SELECT *
FROM TBL FMP
WHERE FMP.FE6_MILEPOST_SEQ_I = 0)
ON FMP.FE6_MILEPOST_I = TPD.CURR_STATION_MP_I
The two sub queries inside works separately but when joined, it throws the following error
[Error] Execution (31: 5): ORA-00904: "FMP"."FE6_MILEPOST_I": invalid identifier
You have to alias your derived table, e.g. like this:
(SELECT FMP.FE6_MILEPOST_I,
FMP.OPERATIONAL_REGION_C,
FMP.OPERATIONAL_REGION_N,
FMP.OPERATING_ZONE_C,
FMP.OPERATING_ZONE_N,
FMP.OPERATING_SUBDIVISION_C,
FMP.OPERATING_SUBDIVISION_N
FROM TBL FMP
WHERE FMP.FE6_MILEPOST_SEQ_I = 0) FMP
The FMP alias that you gave your TBL within the derived table does not "escape" the derived table's nested namespacing scope. I.e. you cannot "see" that table name from outside. Without giving the derived table any name, you can only reference its projected columns without qualification.
Notice that Oracle is one of the few databases that actually allow you to skip aliasing derived tables in the first place, for quick and dirty querying. Even so, I recommend you always alias your derived tables, even in Oracle.
The subquery needs an alias, so you can refer to columns it returns in the outer query.
But here, I would suggest simplifying the FROM clause. Using a subquery does not see useful anyway, so you could just go:
SELECT ...
FROM TABLE TPD
LEFT JOIN TBL FMP
ON FMP.FE6_MILEPOST_SEQ_I = 0
AND FMP.FE6_MILEPOST_I = TPD.CURR_STATION_MP_I
I do not understand why the following query works, although the subquery gives an "invalid identifier" error.
SELECT *
FROM aircraft
WHERE airc_manufact IN (SELECT airc_manufact FROM flight);
My tables look the following (abbreviated):
AIRCRAFT (airc_model (PK), airc_manufact)
FLIGHT (flt_no (PK), airc_model (FK))
If I run the subquery on its own, then I receive an "invalid identifier" error like it should since the airc_manufact is not a column in the flight table.
If I run the whole query, then I do not receive an error. Oracle seems to ignore the subquery and thus give me all row in the aircraft table.
To me, this seems to be a bug because there is an obvious error in the query. Why does the query run? My understanding is that Oracle would first run or evaluate the subquery, and then run the outer query.
You have not qualified your column names. So, you think you are running:
SELECT a.*
FROM aircraft a
WHERE a.airc_manufact IN (SELECT f.airc_manufact FROM flight f);
If f.airc_manufact doesn't exist, then the scoping rules say to look in the outer query. So, what you are really running is:
SELECT a.*
FROM aircraft a
WHERE a.airc_manufact IN (SELECT a.airc_manufact FROM flight f);
That is pretty useless as a filtering clause.
Moral: Always qualify column names in a query, particularly if the query refers to more than one table.
Can anyone help me with the following statement. I'm new to SQL and maybe overlooking the obvious.
I am trying to run the following query
There is a shipments table with the corresponding columns (PROJECTNO, SUPPLIERNO)
I know I don't the to put SHIPMENTS. in front of the names, but this will eventually end up in a multi table query.
SELECT sup1.SHIPMENTS.PROJECTNO, sup2.SHIPMENTS.PROJECTNO
FROM SHIPMENTS sup1, SHIPMENTS sup2
WHERE sup1.SHIPMENTS.PROJECTNO = sup2.SHIPMENTS.PROJECTNO
AND sup1.SHIPMENTS.SUPPLIERNO <> sup2.SHIPMENTS.SUPPLIERNO;
I keep getting the following error.
ORA-00904: "SUP2"."SHIPMENTS"."SUPPLIERNO": invalid identifier
00904. 00000 - "%s: invalid identifier"
*Cause:
*Action:
Error at Line: 160 Column: 34
THanks in advance
Your query should be written as:
SELECT sup1.PROJECTNO, sup2.PROJECTNO
FROM SHIPMENTS sup1 JOIN
SHIPMENTS sup2
on sup1.PROJECTNO = sup2.SHIPMENTS.PROJECTNO AND
sup1.SUPPLIERNO <> sup2.SUPPLIERNO;
First, when using an alias there is no need to specify the table name again. Also, you should use explicit join syntax, with an on condition. The implicit syntax, with the condition in the where clause, is supported, but it is less powerful and more difficult to read.
Change all sup2.SHIPMENTS.SUPPLIERNO to sup2.SUPPLIERNO, and do the same for sup1 alias, and for the other colummns.
You must understand aliasing. Once you alias table TAB as T then you should refer to it as simply T.
In your FROM clause, when you say
FROM SHIPMENTS sup1, SHIPMENTS sup2
you are aliasing the SHIPMENTS table as sup1 and sup2 (as 2 instances of same table). So you need to use sup1 and sup2 as the table name, and the real name (SHIPMENTS) isn't valid, and would be ambiguous anyway, so use:
sup1.SUPPLIERNO --refers to SUPPLIERNO column in SHIPMENTS table aliased as sup1
sup2.PRODUCTNO --refers to PRODUCTNO column in SHIPMENTS table aliased as sup2
there is no such thing as sup2.SHIPMENTS.SUPPLIERNO because there is no such thing as a sup2.SHIPMENTS table
Also, a general rule to keep in mind, in Oracle you can use notation like table.column, schema.table or schema.table.column to refer to tables/views or columns. In this case what you've written amounts to table.table.column which doesn't make sense (unless you were using a nested table).
The reason you must use aliasing here is that it is the only way to join a table to itself. If you use the full table name twice, you'll get ambiguity errors. When you self-join a table, Oracle treats each instance (alias) as a distinct table in the query. I prefer to use aliases like a and b to reduce typos.
SELECT a.PROJECTNO, b.PROJECTNO
FROM SHIPMENTS a JOIN SHIPMENTS b USING(PROJECTNO)
WHERE a.SUPPLIERNO <> b.SUPPLIERNO;