Lightly Seared On The Reality Grill

Random expat geekery from The Low Countries

Browsing Posts tagged SQL

This is more for my own benefit than for anyone else, but I can see this question cropping up a few more times over the next few months. The issue is that I have a table containing an ISO date and have to populate a legacy table in which the date is represented as a ten character string (YYYY-MM-DD).

This works:

select trim(char(year(iso_date))) || '-' ||
       substr(digits(month(iso_date)), 9, 2) || '-' ||
       substr(digits(char(day(iso_date))), 31, 2)
from ...

The digits function returns a fixed-length character-string representation of the absolute value of a number. then all you need to do is identify the bit of the string that you need to use.

flattr this!

I’m not going to criticise anyone for trying to move away from native I/O on the IBM i and into SQL, but I have seen a few eye-watering attempts. So in the spirit of sharing knowledge and making life a bit easier for all of us, here is an example of reading and updating a table using SQL.

Let’s start with the table we’re updating. It’s a very simple table and simply maps the SoldTo/ShipTo combination in the distibution system to a Store number in the retail system. You can build a simplified version of this using the following:

create table
testlib.sqltest
(index integer not null
 GENERATED ALWAYS AS IDENTITY (START WITH 1 INCREMENT BY 1),
 Soldto char (5) not null,
 shipto char (4) not null,
 store numeric (5, 0) not null)

The requirement is that, based on various business rules, some SoldTo numbers in this table need to be changed. In order to keep things simple, the below program applies a simple rule of: If the store number is less than ten, change the SoldTo to 99999. (I know, I said I was keeping things simple).

The program, as it stands, is pretty much as simple as it gets, but there are couple of points that are worth noting explicitly.

Firstly, when we declare the cursor, we need to include a For Update clause to identify which field (or fields) can be updated.

Secondly, in the Update statement, the Where Current of C1 clause applies the update to all records returned by the cursor. That means that flexible mass updates with a minimum of logical mess are now at your fingertips.

     H
     D SqlRecord       DS
     D  SoldTo                        5A
     D  ShipTo                        4A
     D  Store                         5S 0
     D
     D NewSoldTo       S              5A
      /Free

         Exec Sql
            Declare C1 cursor for
               Select SoldTo, ShipTo, Store
               From SqlTest
               For Update of SoldTo;

         Exec Sql
            Open C1;

         Dou SQLSTATE>='02000';
            Exec Sql
               Fetch C1 into :SqlRecord;

            If SQLSTATE<'02000';
               If Store<=10;
                  NewSoldTo='99999';
                  Exec Sql
                     Update SqlTest
                     Set SoldTo = :NewSoldTo
                     Where current of C1;
               Endif;
            Endif;
         Enddo;

         Exec Sql
            Close C1;

         *INLR=*ON;

      /End-Free

flattr this!

Splash I use SQL a lot. Not only embedded within my RPG programs but also interactively to check and maintain data. The IBM i does provide a green-screen interactive SQL session but as soon as you start writing anything more than simple select and update statements, this becomes very cumbersome. The System i Navigator also provides an SQL tool which, while an improvement on the green screen session is still pretty basic.

It is possible, of course, to write your SQL in a source code editor like Notepad++ and then paste it into the System i Navigator SQL tool. Obviously, though, this is not ideal so I was rather pleased to discover that there is a better approach.

I heard about SQuirreL SQL earlier this week and, having finally gotten around to installing it, I have to say that I am very impressed. SQuirreL SQL is open-source SQL client that uses JDBC to connect to pretty much any database you can think of. It’s fast and feature-packed and really is a boon to developers.

In order to get it up and running, you need to first download JTOpen, the open-source version of the IBM Toolbox for Java, and then download and install the SQuirreL Client itself. MC Press Online has a useful walk-through of the steps you need to take to get this all working.

Once you’re in, though, it really is a lovely tool. I am not going to attempt to write a review on the basis of three hours of tinkering, but one thing that has struck me is that the keyboard shortcuts are well worth learning.

Beyond that, I have yet to encounter a task that I can’t complete faster with SQuirreL than with my previous approach.

flattr this!

We’re still on version 6.1 of the IBM i operating system at the moment, so I am making a note of this article for future reference because it looks very useful.

flattr this!

Joining In

No comments

Writing in the Four Hundred Guru (who really do need to change their name!), Ted Hold makes a good point about creating views over normalised tables.

While I’m not a fan of handing ad-hoc query tools to end users, I can think of a few Business Analysts who would benefit from having a simpler database visualisation to cope with.

flattr this!

The IBM i includes several features which are – or can be – incredibly handy but which are not supported by industry standard tools. One example of this is physical files with multiple members. On the i, they provide a very effective mechanism for managing large amounts of similar data (transactions, for example). However, SQL doesn’t support multiple members and, therefore, can usually only access the first member in the table (which is usually the member with the same name as the file/table). This causes problems when people are trying to access i data from external applications and, as a consequence, far too many people end up not taking advantage of multiple members.

It’s a shame because there is a workaround and it’s painfully simple – all you need to do is create an alias.

In the, rather trivial, example below I want to delete transactions out of the INVALID member in file TRANSACTIONS based on various selection criteria provided by the business. So I create an alias, REJECTED. Now I can delete transactions out of the INVALID member by running the delete command over the alias REJECTED.

Set schema LIBRARY;

Create alias REJECTED for TRANSACTIONS(INVALID);

delete from REJECTED
where... ;

drop alias REJECTED;

Granted, this is a pretty basic example, but the general approach – Create Alias; Do Stuff; Drop Alias – will work in any case where you are accessing IBM i data from a non-i environment (such as PHP or Java JDBC).

One final note. It is, of course, possible to simply create a permanent alias and avoid the overhead of repeatedly creating and dropping the temporary one. You do have to be a little bit careful doing this, though, because if you rename a member in the file, the alias will no longer point to it and you would have to remember to either create a new alias or create a new member with the old member name.

My memory is terrible. This is why I prefer to create a temporary alias when I need it and then drop it when I’m done.

flattr this!

When you compile a SQLRPGLE program, the default Commitment Control option is *CHG. This indicates that tables you update will be locked until the changes are committed or rolled back. This is all well and good, but you do need to have journaling switched on for the tables for it to work.

The compiler doesn’t check this so, by default, a program to update an unjournaled table will compile and can be executed. It just won’t make any updates and you will need to dig through the job log to track this down.

The Right Way

What you should do is journal everything and take full advantage of commitment control.

In order to do this, you would need to create a journal receiver and a journal…

CRTJRNRCV JRNRCV(MYLIB/MYRECV) TEXT('My Journal Receiver')
CRTJRN JRN(MYLIB/MYJRN) JRNRCV(MYLIB/MYRECV) TEXT('My Journal')

And start journaling your files…

STRJRNPF FILE(FILEA, FILEB, FILEC, …) JRN(MYLIB/MYJRN) IMAGES(*BOTH) OMTJRNE(*OPNCLO)

When you want to stop journaling a file, you can do this:

ENDJRNPF FILE(*ALL | FILEA, FILEB, FILEC, …) JRN(MYJRN)

Bear in mind that the journal receivers can get pretty big pretty quickly so you will need to talk to your operations folks about disconnecting and purging these on a regular basis.

The Other Way

Of course, you may well be working with a third party application which is not taking advantage of commitment control and, for which, you can’t justify implementing a whole set of journals. This leaves you needing to turn off commitment control for your SQLRPGLE program. There are two ways of doing this:

What you can do, every time you come to compile this program, is ensure that you compile it with COMMIT(*NONE).

This approach works but it does rely on you, and every developer that follows you, remembering to change the COMMIT parameter. To me, this is a guarantee that sooner or later someone will forget and a trivial change will suddenly break a previously reliable program.

It is much better to explicitly turn off commitment control in the program itself, ideally in the header spec. Unfortunately, I’m on release 6.1 and this doesn’t include a compiler option for commitment control in the h-spec, so I am left with the following workaround.

Put this line of code at the start of you program:

exec sql Set Option Commit = *NONE;

Commitment control is now switched off and your SQLRPGLE program will happily update your horrible, unjournaled, third-party table.

flattr this!