• The Four Hundred
  • Subscribe
  • Media Kit
  • Contributors
  • About Us
  • Contact
Menu
  • The Four Hundred
  • Subscribe
  • Media Kit
  • Contributors
  • About Us
  • Contact
  • Existence Tests and Left Exception Joins

    March 23, 2005 Dear Colleagues

    SQL has changed a lot since I first used it in 1984, and I can’t think of a single change that hasn’t been for the better. One of the best improvements, to my way of thinking, is the addition of the JOIN clause in SELECT queries.

    I have never liked the EXISTS predicate. I find it hard to read. Sometimes it is difficult to make EXISTS yield the results I want. Fortunately, I have found that the LEFT EXCEPTION JOIN makes a good substitute for EXISTS in many cases. The left exception join returns rows from the primary table that have no match in the secondary table. There is also a right exception join, which returns rows from the secondary table that have no match in the primary table.

    Suppose I wish to find sales orders that do not belong to a valid customer number. One way to make my request is with the negated IN predicate.

    select * from orderhdr
     where custnbr not in
       (select custnbr from customer)
    

    IN breaks down if there are two or more fields that I have to check. I talked about this problem in “Using SQL to Find Duplicate Records”. The solution I proposed to that challenge was to use the EXISTS predicate.

    Suppose, then, that orders refer to customers by company number and customer number. IN is out, but I can use EXISTS.

    select * from orderhdr as o
        where not exists
             (select * from customer as c
               where c.company = o.company
                 and c.custnbr = o.custnbr)
    

    The LEFT EXCEPTION JOIN equivalent looks more natural to me.

    select o.* from orderhdr as o
      left exception join customer as c
             on o.company = c.company
            and o.custnbr = c.custnbr
    

    It’s almost like the usual syntax I use to join two files. The word left is optional, by the way.

    Let’s complicate the example even more. Let’s say there’s a record code in the customer file that indicates whether a customer is active or inactive. Let’s retrieve orders for non-existent customers and inactive customers. Here’s the query using EXISTS.

    select * from orderhdr as o
       where not exists
             (select * from customer as c
               where c.company = o.company
                 and c.custnbr = o.custnbr
                 and reccd = 'A')
    

    The LEFT EXCEPTION JOIN requires a bit of surgery. We must replace CUSTOMER with a nested query.

    select o.* from orderhdr as o
       left exception join
              (select * from customer
                where reccd = 'A') as c
         on o.company = c.company
        and o.custnbr = c.custnbr
    

    If you prefer the exception join, don’t give up EXISTS just yet. I have had less than stellar success in joining three or more tables with the left exception join.

    Let’s add an order details file and an item file to the query. The order details file may have many records for each order header file record.


    Let’s look for orders that reference a non-existent customer, an inactive customer, or a non-existent item.

    My first attempt at a left exception join looks like this:

    select o.ordernbr, o.company, o.custnbr, d.itemnbr
            from orderhdr as o
            join orderdtl as d
              on o.ordernbr = d.ordernbr
            left exception join (select * from customer
                       where reccd = 'A') as c
              on o.company = c.company
             and o.custnbr = c.custnbr
            left exception join item as i
              on d.itemnbr = i.itemnbr
    

    Here is the equivalent EXISTS query.

    select o.ordernbr, o.company, o.custnbr, d.itemnbr
       from orderhdr as o
       join orderdtl as d
         on o.ordernbr = d.ordernbr
      where not exists
              (select * from customer as c
                where reccd = 'A'
        and o.company = c.company
        and o.custnbr = c.custnbr)
        and not exists
              (select * from item as i
                where d.itemnbr = i.itemnbr)
    

    The problem with this query is that it only returns orders that fail to find an active customer and a valid part number. That does not satisfy the search criteria. The EXISTS version is easily corrected by replacing the AND before the last EXISTS clause with OR.

    select o.ordernbr, o.company, o.custnbr, d.itemnbr
      from orderhdr as o
      join orderdtl as d
        on o.ordernbr = d.ordernbr
     where not exists
             (select * from customer as c
               where reccd = 'A'
       and o.company = c.company
       and o.custnbr = c.custnbr)
        or not exists
            (select * from item as i
              where d.itemnbr = i.itemnbr)
    

    If there’s an easy way to code this query with an exception join, I hope one of you knows it and will write to me. The following works, but I think it’s nasty.

    select o.ordernbr, d.orderline, o.company, o.custnbr, d.itemnbr
      from orderhdr as o
      join orderdtl as d
        on o.ordernbr = d.ordernbr
     exception join
             (select * from customer
               where reccd = 'A') as c
        on o.company = c.company
       and o.custnbr = c.custnbr
     union
    select o.ordernbr, d.orderline, o.company, o.custnbr, d.itemnbr
      from orderhdr as o
      join orderdtl as d
        on o.ordernbr = d.ordernbr
     exception join item as i
        on d.itemnbr = i.itemnbr
    

    The SELECT preceding the UNION looks for orders for invalid or inactive customer numbers. The SELECT following the UNION looks for orders with invalid item numbers. The UNION operator combines the two result sets, eliminating the duplicates in the process.

    with OrderData as (
     select o.ordernbr, d.orderline, o.company, o.custnbr, d.itemnbr
       from orderhdr as o
       join orderdtl as d
         on o.ordernbr = d.ordernbr)
     select o.*
       from OrderData as o
      exception join
              (select * from customer
                where reccd = 'A') as c
         on o.company = c.company
        and o.custnbr = c.custnbr
     union
     select o.*
       from OrderData as o
      exception join item as i
         on o.itemnbr = i.itemnbr
    

    The following might be slightly better, but I’m not thrilled with it either.

    If you’re running i5/OS V5R3, you can also use the EXCEPT operation to find rows in one table that have no match in another table. See Michael Sansoterra’s excellent article “More V5R3 SQL Enhancements” for more information on this.

    Looking for data that does not correlate to other tables is an everyday necessity in information processing installations. It’s good that IBM continues to give us newer ways to find it.

    –Ted

    Share this:

    • Reddit
    • Facebook
    • LinkedIn
    • Twitter
    • Email

    Tags:

    Sponsored by
    WorksRight Software

    Do you need area code information?
    Do you need ZIP Code information?
    Do you need ZIP+4 information?
    Do you need city name information?
    Do you need county information?
    Do you need a nearest dealer locator system?

    We can HELP! We have affordable AS/400 software and data to do all of the above. Whether you need a simple city name retrieval system or a sophisticated CASS postal coding system, we have it for you!

    The ZIP/CITY system is based on 5-digit ZIP Codes. You can retrieve city names, state names, county names, area codes, time zones, latitude, longitude, and more just by knowing the ZIP Code. We supply information on all the latest area code changes. A nearest dealer locator function is also included. ZIP/CITY includes software, data, monthly updates, and unlimited support. The cost is $495 per year.

    PER/ZIP4 is a sophisticated CASS certified postal coding system for assigning ZIP Codes, ZIP+4, carrier route, and delivery point codes. PER/ZIP4 also provides county names and FIPS codes. PER/ZIP4 can be used interactively, in batch, and with callable programs. PER/ZIP4 includes software, data, monthly updates, and unlimited support. The cost is $3,900 for the first year, and $1,950 for renewal.

    Just call us and we’ll arrange for 30 days FREE use of either ZIP/CITY or PER/ZIP4.

    WorksRight Software, Inc.
    Phone: 601-856-8337
    Fax: 601-856-9432
    Email: software@worksright.com
    Website: www.worksright.com

    Share this:

    • Reddit
    • Facebook
    • LinkedIn
    • Twitter
    • Email

    BCD Ships WebSmart 5.1 as IBM Eases Off on WebSphere Where Did I Come From?

    Leave a Reply Cancel reply

Volume 5, Number 12 -- March 23, 2005
THIS ISSUE
SPONSORED BY:

T.L. Ashford
Advanced Systems Concepts
WorksRight Software

Table of Contents

  • Existence Tests and Left Exception Joins
  • Where Did I Come From?
  • Wanted: Native RPG and COBOL Support for Browsers

Content archive

  • The Four Hundred
  • Four Hundred Stuff
  • Four Hundred Guru

Recent Posts

  • Spring IBM i Tech Refreshes Will Come A Bit Later This Year
  • You Are Much More Than Power Systems, And So Are We
  • Startup Seeks The “Golden Path” for IBM i Modernization
  • What Can IBM Do To Make The Future Power S1112 Mini System Compelling?
  • IBM i PTF Guide, Volume 28, Number 15
  • Bob 1.0 Users Bugged By Lack Of One Feature
  • Here Come The AI-Based Code Modernization Offerings
  • Guru: Cohesion First – What A Procedure Should Be Responsible For
  • IBM Offers Trade-Ins On Storage To Grease The Upgrade Skids
  • IBM i PTF Guide, Volume 28, Number 14

Subscribe

To get news from IT Jungle sent to your inbox every week, subscribe to our newsletter.

Pages

  • About Us
  • Contact
  • Contributors
  • Four Hundred Monitor
  • IBM i PTF Guide
  • Media Kit
  • Subscribe

Search

Copyright © 2025 IT Jungle