views:

714

answers:

2

Hey folk my question is quite similar to http://stackoverflow.com/questions/757957/restricting-a-left-join

I have a variation in that request though and the comment didn't allow too many characters hence posting as a new question. I hope this doesn't go against the posting rules/etiquette.

Assuming i have a table SHOP and another table LOCATION. Location is a sort of child table of table SHOP, that has two columns of interest, one is a Division Key (calling it just KEY) and a "SHOP" number. This matches to the Number "NO" in table SHOP.

I tried this left outer join:

SELECT S.NO, L.KEY FROM SHOP S LEFT OUTER JOIN LOCATN L ON S.NO = L.SHOP

But i'm getting a lot of duplicates since there are many locations that belong to a single shop. I want to eliminate them and just get a list of "shop, key" entries without duplicates. any ideas how?

The data is correct but duplicates appear as follows:

SHOP     KEY
 1       XXX
 1       XXX
 2       YYY
 3       ZZZ
 3       ZZZ  etc..

I would like the data to appear as:

SHOP     KEY
 1       XXX
 2       YYY
 3       ZZZ  etc..

SHOP table

 NO
 1       
 2       
 3       

LOCATION table

 LOCATION   SHOP  KEY
   L-1       1    XXX   
   L-2       1    XXX   
   L-3       2    YYY   
   L-4       3    YYY   
   L-5       3    YYY   

(edit: ORACLE 10g Database)

+5  A: 

EDIT Following the update in your scenario

I think you should be able to do this with a simple sub query (though I haven't tested this against an Oracle database). Something like the following

UPDATE shop s
SET divnkey = (SELECT DISTINCT L.KEY FROM LOCATN L WHERE S.NO = L.SHOP)

The above will raise an error in the event of a shop being associated with locations that are in multiple divisions.

If you just want to ignore this possibility and select an arbitrary one in that event you could use

UPDATE shop s
SET divnkey = (SELECT MAX(L.KEY) FROM LOCATN L WHERE S.NO = L.SHOP)
Martin Smith
Nice :) This is why it's important to get more than one angle. Thanks Martin, your solution most definitely satisfies my underlying requirement (But the other answer specifically takes care of removing the duplicates, so going to have to mark that one). Cheers
Kaushik Gopal
+3  A: 

You need to GROUP BY 'S.No' & 'L.KEY'

SELECT S.NO, L.KEY 
FROM SHOP S 
LEFT OUTER JOIN LOCATN L 
ON S.NO = L.SHOP
GROUP BY S.NO, L.KEY
SoftwareGeek
+1 for using `GROUP BY` which is equivalent to `DISTINCT` on Oracle http://asktom.oracle.com/pls/asktom/f?p=100:11:0::::P11_QUESTION_ID:32961403234212 but can sometimes be faster on other engines e.g. Postgres (using hashes instead of sorting.)
vladr
Ok you just made me feel reaally stupid. This works perfectly. Thanks. But any additional comments on why the group by is required at all when the left outer is supposed to take care of this. As in i'm trying to understand how the left outer really works.
Kaushik Gopal
@Kaushik: A LEFT OUTER JOIN is not equivalent to nor does it imply a GROUP BY or DISTINCT. The LEFT JOIN takes all rows from the left (first) table, and joins in all rows from the right (second) table where the join condition is satisfied. In an left *outer* join, if there is no data found in the right table which matches data from the left table the left-table data is still returned with NULLs put in for all right-table data. No grouping is expressed or implied. Personally I'd have used DISTINCT as I think it more clearly specifies intent, but YMMV.
Bob Jarvis
@Bob Thanks for clarifying. I misunderstood what was meant by a LEFT OUTER JOIN. I presumed it to be different from a normal LEFT JOIN. Now i understand them to be the same?For the interwebs: A helpful link by Jeff A on understanding the whole join concept: http://www.codinghorror.com/blog/2007/10/a-visual-explanation-of-sql-joins.html
Kaushik Gopal
@Kaushik - yes, LEFT JOIN and LEFT OUTER JOIN are equivalent because the OUTER keyword is optional. If you specify FULL, LEFT, or RIGHT as the join type you can skip specifying OUTER, but I usually put it in because I think it helps make the code clearer. (I know - I didn't put OUTER into my earlier comment - but, um, I was trying to fit everything into the 600 character limit! Yeah, that's the ticket..! :-)
Bob Jarvis