10

I'm new at working on an as400 and I have a query the joins across 4 tables. The query itself is fine, it runs in STRSQL and displays the results.

What I am in struggling with is getting the query to be able to run programmatically (it will eventually be run from a scheduled CL script).

I tried have creating a physical file that contains the query running it with RUNQRY, but it simply displays the query itself, not the actual result set.

Does anyone know what I am doing wrong?


UPDATE

Thanks everyone for the direction and the resources, with them I was able to reach my goal. In case it helps anyone, this is what I ended up doing (all of this was done in it's own library, ALLOCATE):

  1. Created a source physical file (using CRTSRCPF): QSQLSRC, and created a member named SQLLEAGSEA, with the type of TXT, that contains the SQL statement.

  2. Created another source physical file: QCLSRC, and created a member named POPLEAGSEA, with the type of CLP, that changes the current library to ALLOCATE then runs the query using RUNSQLSTM (more detail on this below). Here is the actual command:

    RUNSQLSTM SRCFILE(QSQLSRC) SRCMBR(SQLLEAGSEA) COMMIT(*NONE) NAMING(*SYS)

  3. Added the CLP to the scheduled jobs (using ADDJOBSCDE), running the following command:

CALL PGM(ALLOCATE/POPLEAGSEA)

With regard to RUNSQLSTM, my research indicated that I wasn't going to be able to use this function, because it didn't support SELECT statements. What I didn't indicate in my question was what I needed to do with the the result - I was going to be inserting the resultant data into another table (had I done that I'm sure the help could have figured that out a lot quicker). So effectively, I wasn't going to be doing an SELECT, my end result is actually an INSERT. So my SQL statement (in SQLLEAGSEA) begins with:

INSERT INTO ALLOCATE/LEAGSEAS

SELECT ... BLAH BLAH BLAH ...

From my research, I gather that RUNSQLSTM doesn't support SELECT because it doesn't have a mechanism to do anything with the results. Once I stopped taking baby steps and realized I needed to SELECT AND INSERT in the same statement, it solved my main problem.

Thanks again everyone!

Community
  • 1
  • 1
Jared
  • 101
  • 1
  • 1
  • 4
  • 3
    I'd start here if you haven't already been there. http://www.mcpressonline.com/sql/using-dynamic-sql-in-cl-part-1running-action-queries.html Good luck! I'm also only marginally functional in the AS400/iseries ecosystem. – David Oct 16 '12 at 19:58
  • 1
    A tip for those new to the platform. You probably don't use an AS/400. IBM hasn't sold an AS/400 since 2000. iSeries and System i were succesor systems, but the current hardware is named an IBM Power System with POWER7+ chips. IBM's Watson played Jeopardy! on Power7 System hardware. The current operating system is called IBM i 7.1. Power Systems can also run multiple copies of AIX, Linux, and/or IBM i, in virtual machines called logical partions ("LPAR"s). – WarrenT Oct 17 '12 at 23:19

6 Answers6

5

The command is RUNSQLSTM to run a static SQL statement in a physical file member or stream file.

It is a non-interactive command so it will not execute sql statements that attempt to return a result set.

If you want more control, including the ability to run interactive statements, see the Qshell db2 utility.

For example:

QSH CMD('db2 -f /QSYS.LIB/MYLIB.LIB/MYSRCFILE.FILE/MYSQL.MBR')

Note that the db2 utility only accepts the *SQL naming convention.

James Allman
  • 40,573
  • 11
  • 57
  • 70
4

QM Query

If all the SQL you need is the single complex SQL statement, and this is what it sounds like, then your best bet is to use Query Management Query (see QM Query manual here).

The results can be directed to a display, a spool file, or a physical file (ie a DB2 table). The default output when run interactively is to the screen, but when run in a (scheduled) batch job it will default to a spool file report.

You can create the QM Query interactively via WRKQMQRY, in prompted mode (much like Query/400) or in SQL mode. Or you can compile the QM Query from source, with the CRTQMQRY command.
To run your QM Query, STRQMQRY command.

RUNSQL cmd

If you are using a system that has IBM i 7.1 fully up-to-date, and has Technology Refresh 4 (TR4) installed, then you could also use the new RUNSQL command to execute a single statement. (see discussion in developerWorks)

SQL Scripting w/ RUNSQLSTM cmd

From CL you can run SQL scripts of multiple SQL statements from a source file member. There is no standard default source file name for this, but QSQLSRC is commonly used. The source member can contain multiple non-interactive SQL statements. This means you cannot use a SELECT statement (directly) since theoretically it will not know where to send the results. CL commands are even allowed if given a CL: prefix. Both SQL and CL statements should be terminated with a semicolon ;. While the SQL statements cannot display data directly to the screen, the same restriction does not apply to the scripted CL commands.

The STRQMQRY command can be embedded in the RUNSQLSTM script, by placing the prefix "CL: " in front of the command. Since STRQMQRY can direct output to the screen, a report, or an output table, this can come in very useful.

Remember that to direct your output from a SELECT query to a file you can use either the INSERT or CREATE TABLE statements.

CREATE TABLE newtbl AS
  ( full-select )
  WITH DATA;

Or, to put the results into a table you create in your job's QTEMP library:

DECLARE GLOBAL TEMPORARY TABLE AS
  ( full-select )
  WITH DATA;

[Note: If you create the source to be used by CRTQMQRY, you are advised to create it as CRTSRCPF yourlib/QQMQRYSRC RCDLEN(91), since the compiler will only use 79 columns of your source data (adding 12 for sequence and change date =91). However for QM Forms, which can be used to provide additional formatting, the CRTQMFORM compiler will use 81 columns so RCDLEN(93) is advised for QQMFORMSRC.]

WarrenT
  • 4,502
  • 19
  • 27
2

RUNQRY is a utility that lets you execute a query that was created by another utility named WRKQRY. If you really want to process SQL statements held in a file try RUNSQLSTM. It uses a source physical file to store the statements, not a database file. The standard name for that source physical file is QQMQRYSRC. To create that file, CRTSRCPF yourlib/QQMQRYSRC. Then you can use PDM to work with that source PF. WRKMBRPDM yourlib/QQMQRYSRC. Use F6 to create a new source member. Make it source type TXT. Then use option 2 to will start an editor called SEU. Copy/paste your SQL statements into this editor. F3 to save the source. Once the source is saved, use RUNSQLSTM to execute it.

Buck Calabro
  • 7,558
  • 22
  • 25
  • QQMQRYSRC is the default source file for QM Queries. QM Query source members generated by the system will begin with non-SQL control records, and should be 1 character short of the standard record length. You would be better off using QSQLSRC for RUNSQLSTM. – WarrenT Oct 17 '12 at 22:54
  • 1
    WRKQRY and RUNQRY are part of Query/400, which IBM has deprecated (ie no longer enhances). Query/400 queries are not SQL, and cannot take advantage of DB2's powerful SQE optimizer. There are virtually no advantages to Query/400, and plenty of advantages to QM Query. Query/400 queries can however be converted to QM Queries before you chuck them ;-) – WarrenT Oct 17 '12 at 23:00
  • Whoops, QSQLSRC is a better choice. I got started explaining QM queries and changed my mind mid-stream. Thanks for the assist. – Buck Calabro Oct 18 '12 at 14:06
2

It is (now) possible to run SQL directly in a CL program without using QM Query, RUNSQLSTM or QShell.

Here is an article that discusses the RUNSQL statement in CL programs...

http://www.mcpressonline.com/cl/the-cl-corner-introducing-the-new-run-sql-command.html

The article contains information on what OS levels are supported as well as clear examples of several ways to use the RUNSQL statement.

Bill M
  • 21
  • 1
1

There is of course a totally different solution: You could write and compile a program containing the statement. It requires some longer reading into, especially if you are new to the platform, but it should give you most flexibility over what you do with results. You can use SQL in C, C++, RPG, RPG/LE, REXX, PL (of which I don't know, what it is) and COBOL. Doing that, you can react in any processable way on results from one query and start/create other queries based on what you get.

Although some oldfashioned RPG-programmers try everything to deny SQL in RPG exists, it is possible today for many cases, to write RPG-programs with SQL only and no direct file access (without F-Specs, for those who know RPG).

If your solution works for you, perfect. If you need to do something else, try a look into this pdf: http://publib.boulder.ibm.com/infocenter/iseries/v5r3/topic/rzajp/rzajp.pdf

The integration into RPG is not too bad. It works with the normal program flow. Would look something like this (in free form):

/free
    // init search values:
    searchval = 'Someguy';
    // so the sql query:
    exec sql
      SELECT colum1, colum2
      INTO :var1, :var2
      FROM somelib/somefile
      WHERE keycol=:searchval;
    // now do something with the values:
    some_proc(var1);
/end-free

In this, var1, var2, and searchval are ordinary RPG-variables. No quoting needed. Works also with datastructures (externally defined e.g., the record format of the file itself fits well). You can work with cursors and loops, too, of course. I feel that RPG-programs tend to be easier to read with this.

NullUserException
  • 83,810
  • 28
  • 209
  • 234
kratenko
  • 7,354
  • 4
  • 36
  • 61
1

This will work in two steps:

 RUNSQL SQL('CREATE TABLE QTEMP/REPORT AS (SELECT +         
          EXTRACT_DATE , SYSTEM, ODLBNM, SUM( +              
          OBJSIZE_MB ) AS LIB_SIZE FROM +                    
          ZSYSCOM/DISKRPTHST WHERE ODLBNM LIKE +             
          ''SIS%'' GROUP BY EXTRACT_DATE, SYSTEM, +          
          ODLBNM ORDER BY LIB_SIZE DESC) WITH +              
          DATA') COMMIT(*NONE) DATFMT(*USA) DATSEP(/)        

 RUNQRY     QRYFILE((QTEMP/REPORT)) OUTTYPE(*PRINTER) +          
          OUTFORM(*DETAIL) PRTDFN(*NO) PRTDEV(*PRINT)        

The first step creates a temporary table result in qtemp and the second step/line runs an adhoc query over just the temporary table to a spool file.

Thanks, Michael Frilot