Mixing "USING" and "ON" in Oracle ANSI join - sql

I wrote an Oracle SQL expression like this:
SELECT
...
FROM mc_current_view a
JOIN account_master am USING (account_no)
JOIN account_master am_loan ON (am.account_no = am_loan.parent_account_no)
JOIN ml_client_account mca USING (account_no)
When I try to run it, Oracle throws an error in the line with "ON" self-join saying: "ORA-25154: column part of USING clause cannot have qualifier".
If I omit the "am" qualifier, it says: "ORA-00918: column ambiguously defined".
What's the best way to resolve this?

The error message is actually (surprise!) telling you exactly what the problem is. Once you use the USING clause for a particular column, you cannot use a column qualifier/table alias for that column name in any other part of your query. The only way to resolve this is to not use the USING clause anywhere in your query, since you have to have the qualifier on the second join condition:
SELECT
...
FROM mc_current_view a
JOIN account_master am ON (a.account_no = am.account_no)
JOIN account_master am_loan ON (am.account_no = am_loan.parent_account_no)
JOIN ml_client_account mca ON (a.account_no = mca.account_no);

My preference is never to use USING; always use ON. I like to my SQL to be very explicit and the USING clause feels one step removed in my opinion.
In this case, the error is coming about because you have account_no in mc_current_view, account_master, and ml_client_account so the actual join can't be resolved. Hope this helps.

The using is cleaner (imo) but it is still desirable to externally refererence the join fields as in the org example or an example like this:
select A.field,
B.field,
(select count(C.number)
from tableC C
where C.join_id = join_id -- wrong answer w/o prefix, exception with.
) avg_number
from tableA A
join tableB B using (join_id);
It gives the wrong answer because the join_id within the subquery implies C.join_id (matching all records) rather than A or B. Perhaps the best way to resolve might be just to allow explicit references with using, having the best of both worlds. Seems like there is a need because of cases like these.

Related

BigQuery, left join

I am stuck on a very simple SQL script. I want to do a LEFT JOIN on Google BigQuery.
SELECT a.name, b.name FROM [bigquery-00000:table1] a LEFT JOIN
[bigquery-00000:table2] b ON b.name = a.name LIMIT 10
And I keep getting an error message:
ON clause must be AND of = comparisons of one field name from each
table, with all field names prefixed with table name. Consider using
Standard SQL .google.com/bigquery/docs/reference/standard-sql/), which
allows non-equality JOINs and comparisons involving expressions and
residual predicates
I don't understand what is wrong with my script. Please help.
I found what was wrong with my script. Wrong table name... sorry.

how to write this query using USING clause. i tried am getting error

SELECT
VENDORS.VENDOR_NAME, INVOICE_LINE_ITEMS.LINE_ITEM_DESCRIPTION
FROM
VENDORS, INVOICE_LINE_ITEMS
USING
LINE_ITEM_DESCRIPTION;
WHERE
(INVOICE_LINE_ITEMS.LINE_ITEM_DESCRIPTION LIKE '%Card%' OR
INVOICE_LINE_ITEMS.LINE_ITEM_DESCRIPTION LIKE '%COBAL%')
How should I write this query properly?
The query you want looks something like this:
SELECT v.VENDOR_NAME, li.LINE_ITEM_DESCRIPTION
FROM VENDORS v JOIN
INVOICE_LINE_ITEMS li
USING (VENDOR_ID)
WHERE li.LINE_ITEM_DESCRIPTION LIKE '%Card%' OR
li.LINE_ITEM_DESCRIPTION LIKE '%COBAL%';
Notes:
I am guessing what the column used for the JOIN really is. I doubt it is a line item description.
USING is part of the syntax for JOIN. Simple rule: Never use commas in the FROM clause; always use explicit JOIN syntax.
Table aliases make the query easier to write and to read.
When using USING, the columns for the JOIN are in parentheses.
Semicolons are only at the end of the SQL statement.
You are getting error because of the ; in your FROM clause as pointed below
FROM
VENDORS, INVOICE_LINE_ITEMS
USING
LINE_ITEM_DESCRIPTION; <-- Here
WHERE ....
It should be
FROM
VENDORS v JOIN INVOICE_LINE_ITEMS i
USING (LINE_ITEM_DESCRIPTION)
WHERE ....

The multi-part identifier "tablename.column " could not be bound

When I used this query above exception has thrown
SELECT FINQDET.InquiryNo,FINQDET.Stockcode,FINQDET.BomQty,FINQDET.Quantity,FINQDET.Rate,FINQDET.Required,FINQDET.DeliverTo,FSTCODE.TitleA AS FSTCODE_TitleA ,FSTCODE.TitleB AS FSTCODE_TitleB,FSTCODE.Size AS FSTCODE_Size,FSTCODE.Unit AS FSTCODE_Unit, FINQSUM.TITLE AS FINQSUM_TITLE,FINQSUM.DATED AS FINQSUM_DATED
FROM FINQSUM , FINQDET left outer join [Config]..FSTCODE ON FINQDET.Stockcode=FSTCODE.Stockcode
WHERE FINQDET.InquiryNo=FINQSUM.INQUIRYNO
ORDER BY FINQDET.Stockcode,FINQDET.InquiryNo
but if I used below query problem solved,
SELECT FINQDET.InquiryNo,FINQDET.Stockcode,FINQDET.BomQty,FINQDET.Quantity,FINQDET.Rate,FINQDET.Required,FINQDET.DeliverTo,FSTCODE.TitleA AS FSTCODE_TitleA ,FSTCODE.TitleB AS FSTCODE_TitleB,FSTCODE.Size AS FSTCODE_Size,FSTCODE.Unit AS FSTCODE_Unit,
FINQSUM.TITLE AS FINQSUM_TITLE,FINQSUM.DATED AS FINQSUM_DATED
FROM FINQSUM As FINQSUM , FINQDET As FINQDET left outer join [Config]..FSTCODE As FSTCODE ON FINQDET.Stockcode=FSTCODE.Stockcode
HERE FINQDET.InquiryNo=FINQSUM.INQUIRYNO
ORDER BY FINQDET.Stockcode,FINQDET.InquiryNo
Please can you explain Why using Alias better than using actual table names
The table [Config]..FSTCODE is qualified with database name which works fine if you use alias. Otherwise you need to qualify full name as it is from different database
Looks like FSTCODE is a table in a different DB. In the first query, though the JOIN uses the DB name to identify the table, the ON statement does not. The second statement adresses this by using an ALIAS
You can also modify the first statement as
left outer join [Config]..FSTCODE
ON FINQDET.Stockcode=[Config]..FSTCODE.Stockcode
An alias allows you to reference a set without using the fullname. It saves you typing and allows you to express contextual information to the reader.

sql join syntax

I'm kind of new to writing sql and I have a question about joins. Here's an example select:
select bb.name from big_box bb, middle_box mb, little_box lb
where lb.color = 'green' and lb.parent_box = mb and mb.parent_box = bb;
So let's say that I'm looking for the names of all the big boxes that have nested somewhere inside them a little box that's green. If I understand correctly, the above syntax is another way of getting the same results that we could get by using the 'join' keyword.
Questions: is the above select statement efficient for the task it's doing? If not, what is a better way to do it? Is the statement syntactic sugar for a join or is it actually doing something else?
If you have links to any good material on the subject I'd gladly read it, but since I don't know exactly what this technique is called I'm having trouble googling it.
You are using implicit join syntax. This is equivalent to using the JOIN keyword but it is a good idea to avoid this syntax completely and instead use explicit joins:
SELECT bb.name
FROM big_box bb
JOIN middle_box mb ON mb.parent_box = bb.id
JOIN little_box lb ON lb.parent_box = mb.id
WHERE lb.color = 'green'
You were also missing the column name in the join condition. I have guessed that the column is called id.
This type of query should be efficient if the tables are indexed correctly. In particular there should be foreign key constraints on the join conditions and an index on little_box.color.
An issue with your query is that if there are multiple green boxes inside a single box you will get duplicate rows returned. These duplicates can be removed by addding DISTINCT after SELECT.

Ambiguity in Left joins (oracle only?)

My boss found a bug in a query I created, and I don't understand the reasoning behind the bug, although the query results prove he's correct. Here's the query (simplified version) before the fix:
select PTNO,PTNM,CATCD
from PARTS
left join CATEGORIES on (CATEGORIES.CATCD=PARTS.CATCD);
and here it is after the fix:
select PTNO,PTNM,PARTS.CATCD
from PARTS
left join CATEGORIES on (CATEGORIES.CATCD=PARTS.CATCD);
The bug was, that null values were being shown for column CATCD, i.e. the query results included results from table CATEGORIES instead of PARTS.
Here's what I don't understand: if there was ambiguity in the original query, why didn't Oracle throw an error? As far as I understood, in the case of left joins, the "main" table in the query (PARTS) has precedence in ambiguity.
Am I wrong, or just not thinking about this problem correctly?
Update:
Here's a revised example, where the ambiguity error is not thrown:
CREATE TABLE PARTS (PTNO NUMBER, CATCD NUMBER, SECCD NUMBER);
CREATE TABLE CATEGORIES(CATCD NUMBER);
CREATE TABLE SECTIONS(SECCD NUMBER, CATCD NUMBER);
select PTNO,CATCD
from PARTS
left join CATEGORIES on (CATEGORIES.CATCD=PARTS.CATCD)
left join SECTIONS on (SECTIONS.SECCD=PARTS.SECCD) ;
Anybody have a clue?
Here's the query (simplified version)
I think by simplifying the query you removed the real cause of the bug :-)
What oracle version are you using? Oracle 10g ( 10.2.0.1.0 ) gives:
create table parts (ptno number , ptnm number , catcd number);
create table CATEGORIES (catcd number);
select PTNO,PTNM,CATCD from PARTS
left join CATEGORIES on (CATEGORIES.CATCD=PARTS.CATCD);
I get ORA-00918: column ambiguously defined
Interesting in SQL server that throws an error (as it should)
select id
from sysobjects s
left join syscolumns c on s.id = c.id
Server: Msg 209, Level 16, State 1, Line 1
Ambiguous column name 'id'.
select id
from sysobjects
left join syscolumns on sysobjects.id = syscolumns.id
Server: Msg 209, Level 16, State 1, Line 1
Ambiguous column name 'id'.
From my experience if you create a query like this the data result will pull CATCD from the right side of the join not the left when there is a field overlap like this.
So since this join will have all records from PARTS with only some pull through from CATEGORIES you will have NULL in the CATCD field any time there is no data on the right side.
By explicitly defining the column as from PARTS (ie left side) you will get a non null value assuming that the field has data in PARTS.
Remember that with LEFT JOIN you are only guarantied data in fields from the left table, there may well be empty columns to the right.
This may be a bug in the Oracle optimizer. I can reproduce the same behavior on the query with 3 tables. Intuitively it does seem that it should produce an error. If I rewrite it in either of the following ways, it does generate an error:
(1) Using old-style outer join
select ptno, catcd
from parts, categories, sections
where categories.catcd (+) = parts.catcd
and sections.seccd (+) = parts.seccd
(2) Explicitly isolating the two joins
select ptno, catcd
from (
select ptno, seccd, catcd
from parts
left join categories on (categories.CATCD=parts.CATCD)
)
left join sections on (sections.SECCD=parts.SECCD)
I used DBMS_XPLAN to get details on the execution of the query, which did show something interesting. The plan is basically to outer join PARTS and CATEGORIES, project that result set, then outer join it to SECTIONS. The interesting part is that in the projection of the first outer join, it is only including PTNO and SECCD -- it is NOT including the CATCD from either of the first two tables. Therefore the final result is getting CATCD from the third table.
But I don't know whether this is a cause or an effect.
I'm afraid I can't tell you why you're not getting an exception, but I can postulate as to why it chose CATEGORIES' version of the column over PARTS' version.
As far as I understood, in the case of left joins, the "main" table in the query (PARTS) has precedence in ambiguity
It's not clear whether by "main" you mean simply the left table in a left join, or the "driving" table, as you see the query conceptually... But in either case, what you see as the "main" table in the query as you've written it will not necessarily be the "main" table in the actual execution of that query.
My guess is that Oracle is simply using the column from the first table it hits in executing the query. And since most individual operations in SQL do not require one table to be hit before the other, the DBMS will decide at parse time which is the most efficient one to scan first. Try getting an execution plan for the query. I suspect it may reveal that it's hitting CATEGORIES first and then PARTS.
I am using Oracle 9.2.0.8.0. and it does give the error "ORA-00918: column ambiguously defined".
This is a known bug with some Oracle versions when using ANSI-style joins. The correct behavior would be to get an ORA-00918 error.
It's always best to specify your table names anyway; that way your queries don't break when you happen to add a new column with a name that is also used in another table.
It is generally advised to be specific and fully qualify all column names anyway, as it saves the optimizer a little work. Certainly in SQL Server.
From what I can gleen from the Oracle docs, it seems it will only throw if you select the column name twice in the select list, or once in the select list and then again elsewhere like an order by clause.
Perhaps you have uncovered an 'undocumented feature' :)
Like HollyStyles, I cannot find anything in the Oracle docs which can explain what you are seeing.
PostgreSQL, DB2, MySQL and MSSQL all refuse to run the first query, as it's ambiguous.
#Pat: I get the same error here for your query. My query is just a little bit more complicated than what I originally posted. I'm working on a reproducible simple example now.
A bigger question you should be asking yourself is - why do I have a category code in the parts table that doesn't exist in the categories table?
This is a bug in Oracle 9i. If you join more than 2 tables using ANSI notation, it will not detect ambiguities in column names, and can return the wrong column if an alias isn't used.
As has been mentioned already, it is fixed in 10g, so if an alias isn't used, an error will be returned.