• The Four Hundred
  • Subscribe
  • Media Kit
  • Contributors
  • About Us
  • Contact
Menu
  • The Four Hundred
  • Subscribe
  • Media Kit
  • Contributors
  • About Us
  • Contact
  • Dynamic Lists In Static SQL Queries

    March 31, 2015 Ted Holt

    Hey, Ted:

    We have an SQL query that can take from one to 13 two-byte codes that become part of an IN clause for row selection. We have no idea which codes they will need to see beforehand; it’s an interactive thing. We are using dynamic SQL. I would like to find a static solution. Any suggestions?

    –Harold

    Sure, Harold. I do this sort of thing from time to time, and I use static SQL to do it.

    Let’s say those two-byte codes are state abbreviations, like the state abbreviations we use in the USA. You probably have a form or display into which the user keys the codes, but I’m going to use a command interface for an example.

    Here’s command AR102, which allows the entry of up to 12 state abbreviations.

    CMD        PROMPT('Print a Customer Report')         
    PARM       KWD(STATE) TYPE(*CHAR) LEN(2) +           
                 SNGVAL((*ALL 'XX')) MAX(12) EXPR(*YES) +
                 PROMPT('State abbreviation(s)')         
    

    We can run queries using commands like these:

    AR102 STATE(CA CO)
    AR102 STATE(TX MN VT)
    AR102 STATE(CA GA NM VT MN CO)
    

    This command runs RPG program AR102R, which uses the dynamic approach you’re using.

    H dftactgrp(*no) actgrp('AR')
    
    Far102p    o    e             printer usropn
    
    D AR102R          pr                  extpgm('AR102R')
    D  inStateList                  26a   const
    D AR102R          pi
    D  inStateList                  26a   const
    
    D String          s            256a   varying template
    
    D cSqlEof         c                   const('02000')
    D Command         s                   like(String)
    D StateList       s                   like(String)
    
    D CustRec       e ds                  extname('QCUSTCDT')
    
       *inlr = *on;
       BuildListOfStates ();
       BuildCursor ();
       BuildReport ();
       return;
    
    P BuildListOfStates...
    P                 b
    
    D Size            ds             2
    D  ListSize                      5i 0
    
    D Offset          s              3u 0
    D Ndx             s              3u 0
    D Quote           c                   const('''')
    D Sep             s              1a   varying
    
        Size = %subst(inStateList:1:2);
        Offset = 1;
    
        StateList = '(';
        For Ndx = 1 to ListSize;
           Offset += 2;
           StateList = StateList + Sep + Quote
                           + %subst(inStateList:Offset:2) + Quote;
           Sep = ',';
        endfor;
        StateList = StateList + ')';
    P                 e
    
    P BuildCursor...
    P                 b
       Command = 'select * from qcustcdt ' +
                 ' where state in ' + StateList +
                 ' order by state, cusnum';
       exec sql  declare c1 cursor for p1;
       exec sql  prepare p1 from :Command;
    P                 e
    
    P BuildReport...
    P                 b
       exec sql  open c1;
       open ar102p;
       dow '1';
          exec sql  fetch c1 into :CustRec;
          if sqlstate >= cSqlEof;
             leave;
          endif;
          write detail;
       enddo;
       close ar102p;
       exec sql  close c1;
    P                 e
    

    The command sends the list of codes to the RPG program as a string. The first two bytes are a signed integer that tells how many values there are in the list. The state abbreviations follow. The BuildListOfStates subprocedure converts the list into the form of an IN clause.

    If I run this command:

    AR102 STATE(CA CO MN)
    

    The RPG program receives this:

    **CACOMN
    

    The two asterisks are a lie. What’s really there is the integer 3 (hexadecimal 0003), which I have no way of accurately representing in text. The RPG program generates this:

    ('CA','CO','MN')
    

    The entire SQL command looks like this:

    select * from qcustcdt
     where state in ('CA','CO','MN') 
     order by state, cusnum
    

    AR102R reads file QCUSTCDT, which is in library QIWS, selecting the rows from the indicated states. This works fine. There’s nothing wrong with it.

    However, if you prefer static SQL, as I do, you can’t build the IN clause dynamically. Here’s a technique that works for me.

    First, I create a temporary table in which to load the codes. One code, one row. Then I refer to that table in the IN clause. Here’s the revised program.

    H dftactgrp(*no) actgrp('AR')
    
    Far102p    o    e             printer usropn
    
    D AR102R          pr                  extpgm('AR102R')
    D  inStateList                  26a   const
    D AR102R          pi
    D  inStateList                  26a   const
    
    D String          s            256a   varying template
    
    D cSqlEof         c                   const('02000')
    
    D CustRec       e ds                  extname('QCUSTCDT')
    
       *inlr = *on;
       BuildListOfStates ();
       BuildCursor ();
       BuildReport ();
       return;
    
    P BuildListOfStates...
    P                 b
    
    D Size            ds             2
    D  ListSize                      5i 0
    
    D Offset          s              3u 0
    D Ndx             s              3u 0
    D State           s              2a
    
        exec sql  declare global temporary table List
           (State char(2))
           with replace;
    
        Size = %subst(inStateList:1:2);
        Offset = 1;
    
        For Ndx = 1 to ListSize;
           Offset += 2;
           State = %subst(inStateList:Offset:2);
           exec sql  insert into session.List values (:State);
        endfor;
    P                 e
    
    P BuildCursor...
    P                 b
       exec sql  declare c1 cursor for
                  select * from qcustcdt
                   where state in (select State from session.List)
                   order by state, cusnum;
    P                 e
    
    P BuildReport...
    P                 b
       exec sql  open c1;
       open ar102p;
       dow '1';
          exec sql  fetch c1 into :CustRec;
          if sqlstate >= cSqlEof;
             leave;
          endif;
          write detail;
       enddo;
       close ar102p;
       exec sql  close c1;
    P                 e
    

    Notice how the BuildListOfStates and BuildCursor subprocedures have changed. BuildListOfStates creates temporary table LIST in QTEMP and writes each code into it. BuildCursor refers to LIST in the IN clause.

    For completeness, here’s the printer file definition.

    A                                      REF(QCUSTCDT)
    A          R DETAIL                    SPACEB(1)
    A            CUSNUM    R              1
    A            LSTNAM    R             +1
    A            INIT      R             +1
    A            STREET    R             +1
    A            CITY      R             +1
    A            STATE     R             +1
    A            BALDUE    R             +1EDTCDE(1)
    

    Share this:

    • Reddit
    • Facebook
    • LinkedIn
    • Twitter
    • Email

    Tags:

    Sponsored by
    Maxava

    Maxava Partner Webinar: Keeping IBM i Resilient in a Hybrid World

    The session will examine why disaster recovery strategies often fail when tested, how IBM Power Virtual Server is being positioned within enterprise architectures, and how organizations are using PowerVS for DR, HA, and production workloads.

    Register Now

    Share this:

    • Reddit
    • Facebook
    • LinkedIn
    • Twitter
    • Email

    Sponsored Links

    LaserVault:  Webinar - IBM i: Intro to Tapeless Backups. April 9
    Chrono-Logic:  Deploy automatically to multiple IBM i and Windows servers with a single click!!
    COMMON:  2015 Annual Meeting & Expo, April 26 - 29, at the Disneyland® Resort in Anaheim, California

    Handling Constraints Revisited RubyGems Are The Foundation Of Success

    Leave a Reply Cancel reply

Volume 15, Number 06 -- March 31, 2015
THIS ISSUE SPONSORED BY:

WorksRight Software
HelpSystems
LaserVault

Table of Contents

  • Handling Constraints Revisited
  • Dynamic Lists In Static SQL Queries
  • RubyGems Are The Foundation Of Success

Content archive

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

Recent Posts

  • Power Systems Still Waiting For The GenAI Bump
  • The IBM i and the Hybrid Cloud World: Things To Keep In Mind
  • CData Adds Db2 for i Support to CDC Tool
  • As I See It: The Cost of Having Ethics
  • Brace Yourself: Another Power Systems Price Hike Coming May 1
  • Updates Announced for IBM i BRMS And SMTP Email Client
  • AI Will Be Front And Center At POWERUp 2026 Next Week
  • IBM i PTF Guide, Volume 28, Number 16
  • Spring IBM i Tech Refreshes Will Come A Bit Later This Year
  • You Are Much More Than Power Systems, And So Are We

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