• The Four Hundred
  • Subscribe
  • Media Kit
  • Contributors
  • About Us
  • Contact
Menu
  • The Four Hundred
  • Subscribe
  • Media Kit
  • Contributors
  • About Us
  • Contact
  • You Can’t Get There from Here

    November 1, 2002 Timothy Prickett Morgan

    Hey, Howard:

    I have a file on my AS/400 that contains flight segments. I need to identify all jobs by departing and final destination airport codes. The file is keyed by our job number and could have from one to four records per job number. It would be easy if every flight was direct, as the departure and destination codes would be on the same record. When the departure and final destination codes are on different records, that makes a search difficult.

    The file details the date of a flight, the departure city, arrival city, flight number, sequence, and a code that indicates if that flight is its final destination. The flight numbers can change between legs of the journey, but a job number field is unique for a set of flights from origination to destination. As an example, I might want to find all flights departing JAX with a final destination of ORL. Oh, SQL Guru, can you show me the light?

    — Alex

    This is a real neat question, because we get to join a table to itself in order to answer the question. In fact, this is probably the best type of question to illustrate the concept of self-joins. First, we are going to need a table to hold the sample data. This table will have the fields FDATE for the flight date, JOBN for the job number, FLTN to hold the flight number, DPC for the departure city, DSC for the destination city, LEG to indicate if it is the final destination and SEQ to indicate the sequence of the flight in the JOB. Records in the table are uniquely keyed by JOBN and SEQ. Here are the SQL statements to create the test table and insert our sample data:

    CREATE TABLE MCEIS.FLIGHTS 
      (FDATE  DATE NOT NULL,
       JOBN   INTEGER NOT NULL,
       FLTN   CHAR(4) NOT NULL,
       DPC    CHAR(3) NOT NULL,
       DSC    CHAR(3) NOT NULL,
       LEG    CHAR(1) NOT NULL,
       SEQ    SMALLINT NOT NULL,
       PRIMARY KEY (JOBN,SEQ));
       
    INSERT INTO MCEIS.FLIGHTS VALUES ('11/01/2002',1,'1321','JAX','ORL','F',1);
    INSERT INTO MCEIS.FLIGHTS VALUES ('11/01/2002',2,'0012','JAX','ATL','C',1);
    INSERT INTO MCEIS.FLIGHTS VALUES ('11/01/2002',2,'0012','ATL','SFX','C',2);
    INSERT INTO MCEIS.FLIGHTS VALUES ('11/01/2002',2,'0091','SFX','JPL','C',3);
    INSERT INTO MCEIS.FLIGHTS VALUES ('11/01/2002',2,'0456','JPL','ORL','F',4);
    INSERT INTO MCEIS.FLIGHTS VALUES ('11/01/2002',3,'9876','ATL','MIA','C',1);
    INSERT INTO MCEIS.FLIGHTS VALUES ('11/01/2002',3,'1132','MIA','ORL','C',2);
    INSERT INTO MCEIS.FLIGHTS VALUES ('11/01/2002',3,'1132','ORL','JAX','C',3);
    INSERT INTO MCEIS.FLIGHTS VALUES ('11/01/2002',3,'1132','JAX','ATL','F',4);
    INSERT INTO MCEIS.FLIGHTS VALUES ('11/01/2002',4,'3213','IAD','LAX','F',1);
    INSERT INTO MCEIS.FLIGHTS VALUES ('11/01/2002',5,'3320','IAD','BWI','C',1);
    INSERT INTO MCEIS.FLIGHTS VALUES ('11/01/2002',5,'5555','BWI','ORD','C',2);
    INSERT INTO MCEIS.FLIGHTS VALUES ('11/01/2002',5,'1254','ORD','DFW','C',3);
    INSERT INTO MCEIS.FLIGHTS VALUES ('11/01/2002',5,'3213','DFW','LAX','F',4);
    INSERT INTO MCEIS.FLIGHTS VALUES ('11/01/2002',6,'0212','JAX','ORL','C',1);
    INSERT INTO MCEIS.FLIGHTS VALUES ('11/01/2002',6,'0412','ORL','ATL','C',2);
    INSERT INTO MCEIS.FLIGHTS VALUES ('11/01/2002',6,'0591','ATL','PHX','F',3);
    

    Here is a table of the information for reference:

    FDATE JOBN FLTN DPC DSC LEG SEQ
    11/01/2002 1 1321 JAX ORL F 1
    11/01/2002 2 12 JAX ATL C 1
    11/01/2002 2 12 ATL SFX C 2
    11/01/2002 2 91 SFX JPL C 3
    11/01/2002 2 456 JPL ORL F 4
    11/01/2002 3 9876 ATL MIA C 1
    11/01/2002 3 1132 MIA ORL C 2
    11/01/2002 3 1132 ORL JAX C 3
    11/01/2002 3 1132 JAX ATL F 4
    11/01/2002 4 3213 IAD LAX F 1
    11/01/2002 5 3320 IAD BWI C 1
    11/01/2002 5 5555 BWI ORD C 2
    11/01/2002 5 1254 ORD DFW C 3
    11/01/2002 5 3213 DFW LAX F 4
    11/01/2002 6 212 JAX ORL C 1
    11/01/2002 6 412 ORL ATL C 2
    11/01/2002 6 591 ATL PHX F 3

    At this point, we have a file called flights that is filled with one day’s worth of data regarding six jobs. First, let’s construct a query that finds all flights that originate from JAX and have a final destination of ORL. To do this, I want to create two sets from the table. The first set will contain all flights that depart JAX. A query that returns all JAX departing flights would be as follows:

    SELECT FDATE, JOBN, DPC, DSC 
          FROM MCEIS.FLIGHTS 
          WHERE DPC='JAX';
    

    That yields the following table:

    FDATE JOBN DPC DSC
    11/01/2002 1 JAX ORL
    11/01/2002 2 JAX ATL
    11/01/2002 3 JAX ATL
    11/01/2002 6 JAX ORL

    The second set contains all flights that have a final destination of ORL. The query to find all flights that have a final destination of ORL is illustrated here:

    SELECT FDATE, JOBN, DPC, DSC 
          FROM MCEIS.FLIGHTS 
          WHERE DSC='ORL' AND LEG='F'
    

    That yields this table:

    FDATE JOBN DPC DSC
    11/01/2002 1 JAX ORL
    11/01/2002 2 JPL ORL

    If you look at the results of query one, we have four flights that depart from JAX: flight numbers 1,2,3, and 6. Query two shows that we have two flights with final destinations of ORL: flight numbers 1 and 2. Now, we want to join the results of query one with query two. The following statement accomplishes that:

    SELECT A.FDATE, A.JOBN, 
      A.FLTN AS ORIGIN_FN, B.FLTN AS DEST_FN, 
      A.DPC AS ORIGIN, B.DSC AS DEST
    FROM MCEIS.FLIGHTS AS A 
          INNER JOIN MCEIS.FLIGHTS AS B 
        ON (A.JOBN=B.JOBN) 
    WHERE B.LEG='F' AND A.DPC='JAX' AND B.DSC='ORL';
    

    That yields this table of information:

    FDATE JOBN ORIGIN_FN DEST_FN ORIGIN DEST
    11/01/2002 1 1321 1321 JAX ORL
    11/01/2002 2 12 456 JAX ORL

    Look at the FROM clause in the above statement and notice that we are selecting from FLIGHTS and naming it A and then joining to FLIGHTS and naming it B. You can join a table to itself in SQL, as long as you give it a unique name so you can tell SQL which columns you want. Next, look at the ON clause of the join. It is specifying that we want to join the sets when the A.JOBN is equal to the B.JOBN. Finally the WHERE clause indicates that we want records from the A table when the DPC=JAX, from the B table when the DSC=ORL, and the LEG=F. This is a perfect example of joining a table to itself to answer a query.



    More Flights of Fancy

    Now, let’s suppose you want to find all flights that go from JAX to ORL, but ORL does not have to be the final leg of the flight. You might think that you could just drop the B.LEG = F from the query. However, look at the results that action would generate:

    FDATE JOBN ORIGIN_FN DEST_FN ORIGIN DEST
    11/01/2002 1 1321 1321 JAX ORL
    11/01/2002 2 12 456 JAX ORL
    11/01/2002 3 1132 1132 JAX ORL
    11/01/2002 6 212 212 JAX ORL

    Take a look at the route of flight 3. It leaves ATL and goes to MIA, then MIA to ORL. It then leaves ORL and goes to JAX and then leaves JAX and goes back to ATL. This flight departs from JAX and it arrives in OLR. However, it never arrives at ORL after leaving JAX. In order to ensure that you see only flights departing JAX and arriving ORL, you need to execute the following query:

    SELECT A.FDATE, A.JOBN, 
      A.FLTN AS ORIGIN_FN, B.FLTN AS DEST_FN, 
      A.DPC AS ORIGIN, B.DSC AS DEST
    FROM MCEIS.FLIGHTS AS A 
    INNER JOIN MCEIS.FLIGHTS AS B 
        ON (A.JOBN=B.JOBN) 
    WHERE A.DPC='JAX' AND B.DSC='ORL' AND A.SEQ<=B.SEQ;
    

    That query yields the following information:

    FDATE JOBN ORIGIN_FN DEST_FN ORIGIN DEST
    11/01/2002 1 1321 1321 JAX ORL
    11/01/2002 2 12 456 JAX ORL
    11/01/2002 6 212 212 JAX ORL

    Because we quantified that the A.SEQ should be less than or equal to the B.SEQ we have eliminated flight 3 from the result set. Remember, the SEQ field tells the sequence of the leg. Now, if we wanted to find only direct flights from JAX to ORL, we simply change the above query to be A.SEQ=B.SEQ. This would result in flights 1 and 6, which are the only flights that can take us from JAX to ORL with no hops in between.



    Retrieving the Routes

    What if we wanted to find the routes for all flights that depart JAX and arrive ORL. The IN clause allows us to search for records that have a value of a field in a set of values. The set of values can be an expression or it can be the result of an SQL statement. The following statement lists the routes of all flights that leave JAX and arrive (at some point) in ORL:

    SELECT * 
    FROM MCEIS.FLIGHTS 
    WHERE JOBN IN 
          (SELECT A.JOBN 
          FROM MCEIS.FLIGHTS AS A 
          INNER JOIN MCEIS.FLIGHTS AS B 
        ON (A.JOBN=B.JOBN) 
          WHERE A.DPC='JAX' AND B.DSC='ORL' AND A.SEQ<=B.SEQ)
    ORDER BY JOBN, SEQ;
    

    SQL will execute the query inside the IN clause to get a set of job numbers. It will then join the set of job numbers to the FLIGHTS table and sequence that result set by the JOBN and SEQ fields. The results look like this table:

    FDATE JOBN FLTN DPC DSC LEG SEQ
    11/01/2002 1 1321 JAX ORL F 1
    11/01/2002 2 12 JAX ATL C 1
    11/01/2002 2 12 ATL SFX C 2
    11/01/2002 2 91 SFX JPL C 3
    11/01/2002 2 456 JPL ORL F 4
    11/01/2002 6 212 JAX ORL C 1
    11/01/2002 6 412 ORL ATL C 2
    11/01/2002 6 591 ATL PHX F 3



    Calculating Hops

    Finally, here is one other interesting piece of information you can gather when looking at the set: the number of stops required before you reach the destination. To calculate this, simply subtract the B.SEQ from the A.SEQ, as illustrated in the following query:

    SELECT A.FDATE, A.JOBN, 
      A.FLTN AS ORIGIN_FN, B.FLTN AS DEST_FN, 
      A.DPC AS ORIGIN, B.DSC AS DEST, 
      B.SEQ-A.SEQ AS STOPS
    FROM MCEIS.FLIGHTS AS A 
      INNER JOIN MCEIS.FLIGHTS AS B 
      ON (A.JOBN=B.JOBN)
    WHERE A.DPC='JAX' AND B.DSC='ORL' AND A.SEQ<=B.SEQ;
    

    That action yields this table of information:

    FDATE JOBN ORIGIN_FN DEST_FN ORIGIN DEST STOPS
    11/01/2002 1 1321 1321 JAX ORL 0
    11/01/2002 2 12 456 JAX ORL 3
    11/01/2002 6 212 212 JAX ORL 0

    The following query displays each flight’s departure city and final destination city and the number of stops on the flight:

    SELECT A.JOBN, A.DPC AS ORIGIN, 
      B.DSC AS DEST, B.SEQ-A.SEQ AS STOPS
    FROM MCEIS.FLIGHTS AS A INNER JOIN MCEIS.FLIGHTS AS B 
      ON (A.JOBN=B.JOBN)
    WHERE A.SEQ=1 AND B.LEG='F';
    

    It is displayed as follows:

    JOBN ORIGIN DEST STOPS
    1 JAX ORL 0
    2 JAX ORL 3
    3 ATL ATL 3
    4 IAD LAX 0
    5 IAD LAX 3
    6 JAX PHX 2

    The A set includes only records that have a SEQ = 1, (start of JOB), and the B set includes only records that have a LEG of F (the final destination).

    Alex, thanks for such a good question, which allowed me to illustrate the power of self joins. I think that most of the readers will be able to find ways to use this technique on their own data.

    — Howard

    Howard F. Arner, Jr. is a writer and consultant for Client Server Development, Inc. You can purchase Howard’s book, iSeries and AS/400 SQL at Work from www.sqlthing.com/books or go to www.sqlthing.com to learn more about using SQL on the AS/400.

    Sponsored By
    RJS SOFTWARE SYSTEMS

    Implement Document Imaging on your iSeries-AS/400 in 30 minutes or less

    Image Server/400 is a Web browser-based document image management system for the iSeries.

    Documents can be quickly scanned and stored in IFS folders, and then located and retrieved for viewing via any Web browser. Integrate with other iSeries-AS/400 applications.

    Visit us at COMMON, Booth 418, call us at 888-RJS-SOFT, or download a FREE fully functional demo from our Web site at

    www.rjssoftware.com

    Share this:

    • Reddit
    • Facebook
    • LinkedIn
    • Twitter
    • Email

    Tags: Tags: mgo_rc, Volume 2, Number 84 -- November 1, 2002

    Sponsored by
    Raz-Lee Security

    Start your Road to Zero Trust!

    Firewall Network security, controlling Exit Points, Open DB’s and SSH. Rule Wizards and graphical BI.

    Request Demo

    Share this:

    • Reddit
    • Facebook
    • LinkedIn
    • Twitter
    • Email

    SQL’s One-Row, One-Column Table Reader Feedback and Insights: We Want More RPG

    Leave a Reply Cancel reply

MGO Volume: 2 Issue: 84

This Issue Sponsored By

    Table of Contents

    • Reader Feedback and Insights: Not All Hex Dumps Are Created Equal
    • Help with RPG II Programs
    • You Can’t Get There from Here

    Content archive

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

    Recent Posts

    • Liam Allan Shares What’s Coming Next With Code For IBM i
    • From Stable To Scalable: Visual LANSA 16 Powers IBM i Growth – Launching July 8
    • VS Code Will Be The Heart Of The Modern IBM i Platform
    • The AS/400: A 37-Year-Old Dog That Loves To Learn New Tricks
    • IBM i PTF Guide, Volume 27, Number 25
    • Meet The Next Gen Of IBMers Helping To Build IBM i
    • Looks Like IBM Is Building A Linux-Like PASE For IBM i After All
    • Will Independent IBM i Clouds Survive PowerVS?
    • Now, IBM Is Jacking Up Hardware Maintenance Prices
    • IBM i PTF Guide, Volume 27, Number 24

    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