• The Four Hundred
  • Subscribe
  • Media Kit
  • Contributors
  • About Us
  • Contact
Menu
  • The Four Hundred
  • Subscribe
  • Media Kit
  • Contributors
  • About Us
  • Contact
  • Guru: Common Table Expressions Can Replace Query Chains

    June 5, 2017 Ted Holt

    Modernization efforts often concentrate on the database and programs. That is well and good, but there is more to modernization. Replacing Query for IBM i with more modern query tools is also important. But what do you do with those queries that people depend on? More confusing, what do you do with query chains?

    A query chain is a series of queries that run one after another, consolidating and reformatting data in temporary physical files, in order to produce a resulting data set, often in report form. It’s not unusual to see small CL programs like the following one:

    PGM
    RUNQRY     QRY(SA001Q)
    RUNQRY     QRY(SA002Q)
    RUNQRY     QRY(SA003Q)
    RUNQRY     QRY(SA004Q) OUTTYPE(*PRINTER)
    ENDPGM

    In this example, the first three queries load physical files with summary information. The last query combines all the data and builds a report.

    Query Purpose Input files Output file
    SA001Q Sum last year sales by item INVHDR, INVLINE SA001OUT
    SA002Q Sum last year sales YTD by item INVHDR, INVLINE SA002OUT
    SA003Q Sum current year YTD sales by item INVHDR, INVLINE SA003OUT
    SA004Q Print one day’s invoiced items INVHDR, INVLINE, SA001OUT, SA002OUT, SA003OUT

    The report looks something like this:

    Item  Qty  Invoice Line    Date    Cust  Last  Last  Current
                                             year  year  YTD    
                                                    YTD          
    A-1     5   10011    2   20170531   101     0     0        8
    A-7     2   10011    3   20170531   101     1     1        6
    B-1     3   10011    1   20170531   101    11     9       12

    Fortunately, converting such query chains into something more modern, something SQL-based, is not difficult. Here’s one way to approach it.

    First, use the Retrieve Query Management Query (RTVQMQRY) command convert each query to SQL. RTVQMQRY reads the query definition and writes comparable SQL to a source physical file.

    RTVQMQRY QMQRY(SA001Q) SRCFILE(MYLIB/SQLSRC) +
                SRCMBR(SA001QSQL) ALWQRYDFN(*YES)

    I chose to put the SQL equivalent of query SA001Q into member SA001QSQL of source physical file SQLSRC in library MYLIB. Be sure to specify ALWQRYDFN(*YES), as this is the parameter that makes RTVQMQRY look for a query definition object.

    Here’s the generated SQL source code for query SA001Q:

    H QM4 05 Q 01 E V W E R 01 03 17/05/31 18:45
    V 1001 050
    V 5001 004 *HEX
    SELECT
      ALL       T02.ITEM, SUM(T02.QUANTITY)
      FROM      MYLIB/TINVHDR T01 INNER JOIN
                MYLIB/TINVLINE T02
      ON        T01.INVNO = T02.INVNO
      WHERE     T01.INVDATE BETWEEN 20160101 AND 20161231
      GROUP BY  T02.ITEM
      ORDER BY  T02.ITEM ASC

    Ignore the lines that precede the SELECT. Copy and paste the SELECT statement into a new source member as a common table expression, named after the output file. Modify as needed.

    with SA001OUT as
       (SELECT
          ALL       T02.ITEM, SUM(T02.QUANTITY) AS QUANTITY01
          FROM      TINVHDR T01 INNER JOIN
                    TINVLINE T02
          ON        T01.INVNO = T02.INVNO
          WHERE     T01.INVDATE BETWEEN 20160101 AND 20161231
          GROUP BY  T02.ITEM),

    I had to add correlation name QUANTITY01, since that’s what the field was called in the query. I also chose to remove the qualifying library names and to delete the ORDER BY clause, which is not needed.

    After converting all four queries, copying, pasting, and tweaking the SQL source, I end up with this:

    with SA001OUT as
       (SELECT
          ALL       T02.ITEM, SUM(T02.QUANTITY) AS QUANTITY01
          FROM      TINVHDR T01 INNER JOIN
                    TINVLINE T02
          ON        T01.INVNO = T02.INVNO
          WHERE     T01.INVDATE BETWEEN 20160101 AND 20161231
          GROUP BY  T02.ITEM),
    SA002OUT as
       (SELECT
          ALL       T02.ITEM, SUM(T02.QUANTITY) AS QUANTITY01
          FROM      TINVHDR T01 INNER JOIN
                    TINVLINE T02
          ON        T01.INVNO = T02.INVNO
          WHERE     T01.INVDATE BETWEEN 20160101 AND 20160531
          GROUP BY  T02.ITEM),
    SA003OUT as
       (SELECT
          ALL       T02.ITEM, SUM(T02.QUANTITY) AS QUANTITY01
          FROM      TINVHDR T01 INNER JOIN
                    TINVLINE T02
          ON        T01.INVNO = T02.INVNO
          WHERE     T01.INVDATE BETWEEN 20170101 AND 20170531
          GROUP BY  T02.ITEM)
    
    SELECT
                T02.QUANTITY, T01.INVNO, T02.LINENO, T01.INVDATE,
                T01.CUSTNO, T03.QUANTITY01, T04.QUANTITY01, 
                T05.QUANTITY01
      FROM      TINVHDR T01 LEFT OUTER JOIN
                TINVLINE T02
      ON        T01.INVNO = T02.INVNO LEFT OUTER JOIN
                SA001OUT T03
      ON        T02.ITEM = T03.ITEM LEFT OUTER JOIN
                SA002OUT T04
      ON        T02.ITEM = T04.ITEM LEFT OUTER JOIN
                SA003OUT T05
      ON        T02.ITEM = T05.ITEM
      WHERE     T01.INVDATE = 20170531
      ORDER BY  T02.ITEM ASC;

    The parts in red are modifications. Notice also that I removed the library names, as I am wild about using the library list. In fact, I had to remove the library names from the work files, otherwise the main SELECT (the last one) would have read physical files SA001OUT, SA002OUT, and SA003OUT instead of the common table expressions of the same names.

    Where you go from here is up to you. Modify the SQL as you wish. Put your new SQL in a stored procedure. Embed it in an RPG program. Run it in a GUI query tool.

    This is not the only way to convert a query chain to SQL, but it’s an easy, straightforward way. It probably won’t perform any worse than the queries it replaced, and now you have something you can work with.

    RELATED STORY

    Where Do Library Lists Reside?

    Share this:

    • Reddit
    • Facebook
    • LinkedIn
    • Twitter
    • Email

    Tags: Tags: 400guru, Four Hundred Guru, Guru, IBM i, SQL

    Sponsored by
    Rocket Software

    Meet digital age demands while maximizing your IT investment.

    Future-proof your mission-critical applications with Rocket® Solutions for IBM® i that keep your business ahead of the curve.

    Learn More

    Share this:

    • Reddit
    • Facebook
    • LinkedIn
    • Twitter
    • Email

    Mad Dog 21/21: King Solomon’s Mimes Understanding IBM i Options For High Availability

    4 thoughts on “Guru: Common Table Expressions Can Replace Query Chains”

    • Rusty Gadberry says:
      June 5, 2017 at 10:48 am

      Ted, I prefer a more inline approach using join table. Seems to run much faster.

      SELECT T02.QUANTITY, T01.INVNO, T02.LINENO, T01.INVDATE,
      T01.CUSTNO, IFNULL(T03.QUANTITY01,0), IFNULL(T04.QUANTITY01),
      IFNULL(T05.QUANTITY01)
      FROM TINVHDR T01
      JOIN TINVLINE T02 ON T01.INVNO = T02.INVNO
      JOIN TABLE( SELECT SUM(T02.QUANTITY) AS QUANTITY01
      FROM TINVHDR X
      JOIN TINVLINE T02 ON T02.INVNO = X.INVNO
      WHERE X.INVNO = T01.INVNO
      AND X.INVDATE BETWEEN 20160101 AND 20161231
      ) ON 1=1 AS T03
      JOIN TABLE( SELECT SUM(T02.QUANTITY) AS QUANTITY01
      FROM TINVHDR X
      JOIN TINVLINE T02 ON T02.INVNO = X.INVNO
      WHERE X.INVNO = T01.INVNO
      AND X.INVDATE BETWEEN 20160101 AND 20160531
      ) ON 1=1 AS T04
      JOIN TABLE( SELECT SUM(T02.QUANTITY) AS QUANTITY01
      FROM TINVHDR X
      JOIN TINVLINE T02 ON T02.INVNO = X.INVNO
      WHERE X.INVNO = T01.INVNO
      AND T01.INVDATE BETWEEN 20170101 AND 20170531
      ) ON 1=1 AS T05
      WHERE T01.INVDATE = 20170531
      ORDER BY T02.ITEM ASC;

      Reply
    • Rusty Gadberry says:
      June 5, 2017 at 10:57 am

      Little typo error on the IFNULL, but you should get the jest of it.

      Reply
    • Allan Garcia says:
      June 9, 2017 at 5:23 pm

      Hi Ted, is it possible to create unique clustered indexes on a view of multiple joined tables?

      Reply
      • Ted Holt says:
        November 13, 2017 at 3:58 pm

        Indexes are created over tables, Allan. Not views. So, no, I don’t think it is possible.

        Reply

    Leave a Reply Cancel reply

TFH Volume: 27 Issue: 37

This Issue Sponsored By

  • BCD Software
  • Connectria
  • Remain Software
  • International i-Power 2017
  • WorksRight Software

Table of Contents

  • IBM i And AIX Won’t Get Power9 Until 2018
  • Understanding IBM i Options For High Availability
  • Guru: Common Table Expressions Can Replace Query Chains
  • Mad Dog 21/21: King Solomon’s Mimes
  • The App Dev World According To Gapp

Content archive

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

Recent Posts

  • POWERUp 2025 –Your Source For IBM i 7.6 Information
  • Maxava Consulting Services Does More Than HA/DR Project Management – A Lot More
  • Guru: Creating An SQL Stored Procedure That Returns A Result Set
  • As I See It: At Any Cost
  • IBM i PTF Guide, Volume 27, Number 19
  • IBM Unveils Manzan, A New Open Source Event Monitor For IBM i
  • Say Goodbye To Downtime: Update Your Database Without Taking Your Business Offline
  • i-Rays Brings Observability To IBM i Performance Problems
  • Another Non-TR “Technology Refresh” Happens With IBM i TR6
  • IBM i PTF Guide, Volume 27, Number 18

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