views:

247

answers:

3

I'm needing to select first and last name in a table which is working fine in the following SQL, but the part that isn't working is the NVL function. The file should show all pilots at a company that fly helicopters and IF they don't have a licence the field HT_NAME should come up as 'N/A' and the field for end hours flown should be 0. I've put NVL function in as my text details but it still isn't working. Have i made a syntax error? Help would be appreciated.

Select E.EMP_NBR, E.EMP_FIRSTNAME || ' ' || E.EMP_LASTNAME, E.EMP_PILOT,
       ED.HT_NBR, NVL(HT.HT_NAME, 'N/A'), NVL(ED.END_HRS_FLOWN, 0),
       ED.END_LAST_ANNUAL_REVIEW_DATE
From  ENDORSEMENT ED, EMPLOYEE E, HELICOPTER_TYPE HT
WHERE HT.HT_NBR = ED.HT_NBR (+)
ORDER BY ED.END_HRS_FLOWN DESC, E.EMP_FIRSTNAME || ' ' || E.EMP_LASTNAME ASC;

should make employees who are not pilots appear with a N/A under heli type and 0 under hours flown. It isn't working - even though I have tried multiple things to repair it.

+1  A: 

You have three tables and only one join condition; you need a join between Employee and Endorsement. Without that, you are getting a cross-product or Cartesian join between those tables.

With N tables (N > 0), you need J = N-1 join conditions at minimum. You have N = 3 tables, but J = 1 join conditions - which is too few. (There are various reasons why you might need J > N - 1, but the main one is because you need to join two columns between two tables. If you count each 'A.Col1 = B.Col2' condition as a separate join condition, then you need J > N-1; if you count the pair of conditions 'A.Col1 = B.Col2 AND A.Col3 = B.Col4' as a single join condition, then you still only need J = N-1 conditions. )

Ideally, you should also move away from the archaic, non-standard outer join notation using '(+)' and use the standard SQL joins.


The notation is a secondary issue. Every row in Employee is being joined with every row in Endorsement - and then that cross-product is being outer-joined with Helicopter_type. This is (almost certainly) not the query that is required.

You probably need to add some variation of this to the WHERE clause:

AND E.EMP_NBR = ED.EMP_NBR

(where the actual column in the Endorsement (ED) table is not shown in the query, so 'ED.EMP_NBR' is a guess).

Amongst other effects, if there are any helicopter pilots in the database, then every employee record is being joined with the endorsement for a pilot some of the time, and the sort order means that those records will be shown before the myriad records which show that the pilots don't have helicopter endorsements and that non-pilots don't have helicopter records, etc...

Jonathan Leffler
this was the way i've been taught, thank you though ill look elsewhere online for a different way to join.
Mila
+1 for the recommendation on using JOIN syntax. This illustrates precisely one of the benefits of JOINs over the old syntax: clarity/readability.
DCookie
@DCookie: clarity and readability are not inherent qualities of the ANSI join syntax. I have been an Oracle programmer for 20 years, and find much of the ANSI syntax nearly incomprehensible. Without any training in the new syntax, you might as well be writing in Greek, much of the time.
AndyDan
@AndyDan, as someone who, after nearly 20 years on Oracle finally bit the bullet and weaned myself off the old syntax in the past 2 years, I have to disagree. Your finding it incomprehensible is most likely, IMO, simply being in unfamiliar territory. It's a sink/swim process - throw yourself in, refuse to use the old syntax, convert it to the new style when confronted with it, and you'll find yourself loving it. It's actually in your own self interest to do so.
DCookie
@AndyDan, as a side note, I had no training in it. There are TONS of examples out there, tutorials, books. Spend an hour a day investing in yourself. Don't wait for someone else to do it for you.
DCookie
@DCookie, your first reply makes the same point I did, that it's incomprehensible because it's unfamiliar, so it sounds like you agree, not disagree, with what I said.
AndyDan
I would love to start using it, but I don't work alone, and I actually know more about the new syntax than anybody I work with. It wouldn't surprise me if most of them didn't even know it existed. It's a very hidebound group I work with, and I'm the newbie (although I've been here 6 years). I question everything that doesn't make sense to me, and half the time the answer is just that "we've always done it this way and it works, why change it?"So, I'm learning what I can in my "copious" free time, but it will be difficult to get others to start using the new syntax, too.
AndyDan
@AndyDan... I feel your pain. All I can suggest is for you to make time for yourself as you are able and learn it. If you can do that, then the benefits will make themselves clear to you. At that point, you can start making an effective case to your coworkers as to the benefits of moving in that direction. If you don't, you'll find yourself one day telling the newbie that "we've always done it this way". My only point is that as someone who has worked both sides of the syntax, I find the ANSI syntax by far more clear and readable.
DCookie
A: 

Check whether HT_NAME and END_HRS_FLOWN were having null values or not for the rows you expect N/A or 0

Edit 1

In Oracle, the NVL function lets you substitute a value when a null value is encountered.

The syntax for the NVL function is:

NVL( string1, replace_with )

string1 is the string to test for a null value.

replace_with is the value returned if string1 is null.

If the value is not null, it will return same value

Bharat
they do! thank you though!
Mila
+1  A: 

As @Jonathan said, you need to add something to the WHERE clause to tell the database how to match up EMPLOYEE with ENDORSEMENT. For purposes of discussion we'll use the EMP_NBR field on both, but you'll need to change the query around to use the field that's correct. We also need to know what field tells you if an employee has a valid license. I'm guessing it's something on the ENDORSEMENT table - let's call it ENDORSEMENT.LICENSE_TYPE for purposes of discussion. Once you know that you can use the NVL2 function to alter the values returned by the query appropriately, as follows:

SELECT E.EMP_NBR,
       E.EMP_FIRSTNAME || ' ' || E.EMP_LASTNAME AS FIRST_LAST_NAME,
       E.EMP_PILOT, 
       ED.HT_NBR,
       NVL2(ED.LICENSE_TYPE, HT.HT_NAME, 'N/A') HELO_TYPE,
       NVL2(ED.LICENSE_TYPE, ED.END_HRS_FLOWN, 0) FLOWN_HOURS, 
       ED.END_LAST_ANNUAL_REVIEW_DATE 
  FROM ENDORSEMENT ED,
       EMPLOYEE E,
       HELICOPTER_TYPE HT 
  WHERE HT.HT_NBR = ED.HT_NBR (+) AND
        ED.EMP_NBR = E.EMP_NBR (+)
  ORDER BY ED.END_HRS_FLOWN DESC,
           E.EMP_LASTNAME ASC,
           E.EMP_FIRSTNAME ASC;

I also changed the ORDER BY clause to get the employees ordered in a more normal manner.

Share and enjoy.

Bob Jarvis
Interesting point - I would not have put the second outer join notation in, but it probably is necessary to have an outer join between Employee and Endorsement; I wonder, though, if the join between Endorsement and Helicopter_Type should be an inner join, after all? Basically, that's a detail for the OP to resolve, though.
Jonathan Leffler
Hi, thank you for that, the thing is the employee table doesnt have any PK or FK i can use to join it to the other tables thats why i didnt create a join for it, if theres no PK or FK available can you still join them? i was told otherwise! i have been told that IF there is no foreign key available for the join then you can't join two tables.
Mila
Oh actually that works you are right, in the licence field you added i put EMP_PILOT field, but this isn't a NULL it's a CHAR. If they ARE a pilot its a Y if not it shows up as a N. So i don't know if NVL will work based on that since there's no NULL.
Mila
@Mila: to answer your questions - 1) you can join tables on any fields you care to use. However, there needs to be some fields that the tables in question have in common in order for the join to make sense. What fields do EMPLOYEE and ENDORSEMENT have in common? 2) You're correct - if EMP_PILOT is not null then using NVL on it will have no effect.
Bob Jarvis