I have a query SELECT A.ID, B.ID FROM A, B that works fine.
As soon as I add FETCH FIRST n ROWS ONLY to it, the query fails with the error message
SQL Error [918] [42000]: ORA-00918: column ambiguously defined
As far as I understand, the error refers to an ambiguous SELECT clause and should not be caused by a FETCH FIRST n ROWS ONLY.
Do I miss something that justifies this behaviour? Or is this a bug?
I know that I can omit this behaviour when I specify an explicit column alias. I want to know, why SELECT A.ID, B.ID FROM A, B works, while SELECT A.ID, B.ID FROM A, B FETCH FIRST 10 ROWS ONLY doesn't.
The Oracle version is 12.1.0.2.0
This is documented in oracle documents:
Restrictions on the row_limiting_clause
If the select list contains columns with identical names and you
specify the row_limiting_clause, then an ORA-00918 error occurs. This
error occurs whether the identically named columns are in the same
table or in different tables. You can work around this issue by
specifying unique column aliases for the identically named columns.
Even though SELECT query works, after using FETCH FIRST|NEXT, it will throw error if two of the column names are same.
You should just assign different alias names for all columns in SELECT clause.
Learn to use proper, explicit, **standard* JOIN syntax. Never use commas in the FROM clause. But that is not your problem.
You have two columns with the same alias. Simply use as to assign new aliases:
SELECT A.ID as a_id, B.ID as b_id
What you are observing may be a bug. The code seems to work on other versions of Oracle.
Related
This is my query. But I am getting following error.
Select customer_info.CUSTOMER_ID, customer_info.NAME, Customer_Hierarchy_API.Get_Description(Cust_Hierarchy_Struct_API.Get_Hierarchy_Id(CUSTOMER_ID))
from CUST_ORD_CUSTOMER_ENT
JOIN customer_info ON
customer_info.customer_id = cust_ord_customer_ent.customer_id;
ORA-00918: column ambiguously defined
00918. 00000 - "column ambiguously defined"
*Cause:
*Action: Error at Line: 1 Column: 137
Cust_Hierarchy_Struct_API.Get_Hierarchy_Id(CUSTOMER_ID)
You need to specify which table to take the CUSTOMER_ID column from, as that column name exists in two differnt tables being used (Oracle won't do it for you, programming languages hate ambiguity, so should you).
In your case it doesn't matter which, but you have to choose one.
Cust_Hierarchy_Struct_API.Get_Hierarchy_Id(customer_info.CUSTOMER_ID)
As a principle, never refer to a column on its own, always fully qualify it with the table name or alias. If when you can, don't; it's sloppy and leads to problems as/when the code or database strucutre evolves.
Another solution is the USING clause:
Select ci.CUSTOMER_ID, ci.NAME,
Customer_Hierarchy_API.Get_Description(Cust_Hierarchy_Struct_API.Get_Hierarchy_Id(CUSTOMER_ID))
from CUST_ORD_CUSTOMER_ENT coc join
customer_info ci
using (customer_id);
USING allows you to mention the join keys without having to qualify the reference. After all, the value is the same regardless of which table the value comes from, based on the JOIN condition.
I never notice below before:
SELECT A,*
FROM Table
ORDER BY A
It gives me the Ambiguous column name error. The * of course contains A, but will sql server take the same column A in above query as two different columns? Is this the reason behind that?
it is because the output has the same name if you did
SELECT A AS A_STANDS_ALONE,*
FROM Table
ORDER BY A
It will work
If you are looking for yes/no answer, then 'YES', you are right.
SQL Selects A column twice, one by explicit and one by the implicit * call.
SQL doesn't understand which one you want to sort by.
The first comment to your post shows that you can use an alias for the column.
Consider the following statement:
SELECT a.*
FROM tblA a
WHERE a.Name = #Name
UNION
(SELECT a.*
FROM tblB
WHERE a.Name = #Name)
Notice that range variables (aka aliases) for two different tables have been given the same name.
Is there any potential for conflict or ambiguity in doing this? Should all range variables (aliases) be given a unique name within the statement e.g.:
SELECT a.*
FROM tblA a
WHERE a.Name = #Name
UNION
(SELECT b.*
FROM tblB
WHERE b.Name = #Name)
Experience has shown that this has worked so far... that the scope of each range variable (alias) does not appear to span across the UNION, but is this dependent on unsupported behavior, or do range variables (aliases) have formally defined scope relevant to cases like this?
You threw me with the term "range variable". I've always seen that construct called an "alias".
I'm no expert on SQL standards, but I can't fathom an interpretation where a database engine would ever have a problem with re-used table aliases. Each SELECT statement before and after the UNION is just that - a fully functioning, complete SELECT statement. The two statements are wholly independent from one another - neither knows anything about the other. There is no way to correlate a row from the first query with a row from the second, so I don't see how the aliases could interfere with one another.
You have demonstrated it works on SQL Server.
I tried it on SQL Fiddle, and it works with MySQL, PostgreSQL, and SQLite. Unfortunately Oracle and MS SQL Server are broken on the fiddle site, so no way to test there.
I know you cannot use a alias column in the where clause for T-SQL; however, has Microsoft provided some kind of workaround for this?
Related Questions:
Unknown Column In Where Clause
Can you use an alias in the WHERE clause in mysql?
“Invalid column name” error on SQL statement from OpenQuery results
One workaround would be to use a derived table.
For example:
select *
from
(
select a + b as aliased_column
from table
) dt
where dt.aliased_column = something.
I hope this helps.
Depending on what you are aliasing, you could turn it into a user defined function and reference that in both places. Otherwise your copying the aliased code in several places, which tends to become very ugly and means updating 3+ spots if you are also ordering on that column.
I'm trying to create a sql query, but there is this error:
Ambiguous column name 'description'.
Its because this column occurs in both tables.
if I remove the description from the query, it works.
I tried to rename the description-field "AS description_pointer", but the error still occurs.
SELECT TOP 1000 [activityid]
,[activitytypecodename]
,[subject]
,[regardingobjectid]
,[contactid]
,[new_crmid]
,[description] AS description_pointer
FROM [crmtestext_MSCRM].[dbo].[FilteredActivityPointer] as I
Left JOIN [crmtestext_MSCRM].[dbo].[FilteredContact]
ON I.[regardingobjectid] = [crmtestext_MSCRM].[dbo].[FilteredContact].[contactid]
WHERE new_crmid not like '%Null%' AND activitytypecodename like '%E-mail%'
Both tables coming into play in the query have a column named description. You RDBMS cannot guess which column table you actually want.
You need to prefix the column name with the table name (or table alias) to disambiguate it.
Bottom line, it is a good practice to always prefix column names with table names or aliases as soon as several tables come into play in a query. This avoids the issue that you are seeing here and make the queries easier to understand for the poor souls that have no knowledge of the underlying schema.
Here is an updated version of your query with table aliases and column prefixes. Obviously you need to review each column to put the correct alias:
SELECT TOP 1000
i.[activityid]
,i.[activitytypecodename]
,i.[subject]
,c.[regardingobjectid]
,c.[contactid]
,c.[new_crmid]
,c.[description] AS description_pointer
FROM [crmtestext_MSCRM].[dbo].[FilteredActivityPointer] as i
Left JOIN [crmtestext_MSCRM].[dbo].[FilteredContact] as c
ON i.[regardingobjectid] = c.[contactid]
WHERE i.new_crmid not like '%Null%' AND i.activitytypecodename like '%E-mail%'