What does this odd use of NVL in a comparison do?

The TOAD query optimizer recommended changing this test:
(NOT (sites.pay_site_flag = 'N' AND sites.purchasing_site_flag = 'Y'))
to this:
(sites.pay_site_flag <> NVL ('N', UID) OR sites.purchasing_sige_flag <> 'Y')
both sites.pay_site_flag and sites.purchasing_site_flag allow nulls, so the logical contrapositive is not valid.
Testing seems to show that the query optimizer test returns the same result as the original test, but why? I don't understand how NVL ('N', UID) can ever evaluate to anything but 'N', and how can that be useful in this comparison?
Edited by: Pete Hall on May 6, 2012 10:32 AM
Edited by: Pete Hall on May 6, 2012 11:12 AM
Edited by: Pete Hall on May 6, 2012 11:13 AM

>
That's true, and I did construct the truth table. It's equally true, if I substitute a literal 'N' in place of NVL ('N', UID), so what subtle difference does it make if the NVL function is used instead of the literal 'N'? I suppose it's possible that the TOAD optimizer just pulled that out of the air for no reason, but it seems unlikely.
>
For this example the use of NVL appears to be unnecessary. Can't tell for certain since the example that uses NVL also uses 'UID' which isn't explained anywhere; where did TOAD come up with 'UID'?
The most likely explanation is that the template that TOAD uses includes NVL to handle cases where the NVL actually is necessary. And for cases where NVL isn't needed, and doesn't alter the results, it doesn't matter if it is left in. That could allow TOAD to use one template for all use cases rather than add code to determine the use cases where NVL isn't needed.
Note that your original example
(NOT (sites.pay_site_flag = 'N' AND sites.purchasing_site_flag = 'Y'))is often misinterpreted as meaning the NEGATION of the inner AND condition but testing will show that it is not. You should always use a truth table and full testing to make sure you get exactly what you want.
Since there are two variables and they can each have three values there are nine possible combinations
with q as (SELECT 1 TEST, 'N' PFLAG, 'Y' SFLAG FROM DUAL
           UNION ALL
           SELECT 2 TEST, 'Y' PFLAG, 'Y' SFLAG FROM DUAL
           UNION ALL
           SELECT 3 TEST, NULL PFLAG, 'Y' SFLAG FROM DUAL
           UNION ALL
           SELECT 4 TEST, 'N' PFLAG, 'N' SFLAG FROM DUAL
           UNION ALL
           SELECT 5 TEST, 'Y' PFLAG, 'N' SFLAG FROM DUAL
           UNION ALL
           SELECT 6 TEST, NULL PFLAG, 'N' SFLAG FROM DUAL
           UNION ALL
           SELECT 7 TEST, 'N' PFLAG, NULL SFLAG FROM DUAL
           UNION ALL
           SELECT 8 TEST, 'Y' PFLAG, NULL SFLAG FROM DUAL
           UNION ALL
           SELECT 9 TEST, NULL PFLAG, NULL SFLAG FROM DUAL
SELECT * FROM Q WHERE
   (NOT (PFLAG = 'N' AND SFLAG = 'Y'))
TEST,PFLAG,SFLAG
2,Y,Y
4,N,N
5,Y,N
6,,N
8,Y,
              The inner AND condition
   (PFLAG = 'N' AND SFLAG = 'Y')is TEST #1 of 9 possible combinations.
It is natural to think that if you negate that with the NOT condition that you should get records that correspond to the other 8 conditions.
But if you look at the above results you can see that you only get results matching tests 2, 4, 5, 6 and 8.
Those DO NOT include tests 3 (PFLAG IS NULL and SFLAG = 'Y'), 7 (PFLAG = 'N' but SFLAG IS NULL) or 9 (both flags are NULL).
That is the way NULLs can affect things.
If you really need the NEGATION of the inner AND condition you need to specifically code for the null value combinations.
to mean 'include all records with pay_site_flag IN (null, 'Y') OR purchasing_site_flag IN (null, 'N') but that is NOT what your condition does.
The example provides
If you did the truth table and testing

Similar Messages

Maybe you are looking for