fhg
Volume 11, Number 2 -- January 12, 2011

Closing the Gaps

Corrected: January 12, 2011

Hey, Ted:

We have a database file to which records are added throughout the day. The key is a five-digit packed decimal whole number, and the program that writes to the file increments this number when adding a new record to the file. During the day, another program processes and deletes records throughout the file, leaving gaps between sequence numbers. At the end of each day, we would like to renumber the remaining records, beginning again at sequence number one, to remove the gaps and be prepared for a fresh start the next day. Can we use an SQL UPDATE statement to renumber the sequence numbers?

--Brian


Sure, it's possible, but with one UPDATE command? That depends. Let's consider some possibilities.

First, let's set the stage. Assume 50 records were written to the file during the day, and all but four--sequence numbers 1, 4, 12, and 17--were processed and deleted from your file.

If the arrival sequence coincides with the sequence number sequence, you can probably get away with one UPDATE. (I can't take credit for this technique. I learned it from Joe Celko. Visit this site and search for CloseMotorpoolGaps.)

D ReSeqUpd1       pr                  extpgm('RESEQUPD1')
D   ouStatus                     8a
D ReSeqUpd1       pi
D   ouStatus                     8a

D SqlEof          c                   const('02000')
D AllOK           c                   const('00-00000')
D UnexpectedError...
D                 c                   const('99-99999')

 /free
     *inlr = *on;
     ouStatus = AllOK;

     monitor;

        exec sql
           update reseq as a
              set a.sequence =
                      (select count(b.sequence)
                         from reseq as b
                        where b.sequence <= a.sequence);
        if SqlState > SqlEof;
           ouStatus = '10-' + SqlState;
           return;
        endif;

     on-error;
        ouStatus = UnexpectedError;
     endmon;

     return;

I say probably, because there is no guarantee the system will process the records in arrival sequence. However, since the entire file will be updated (i.e., there is no WHERE clause), chances are pretty close to certain that the system will update in arrival sequence.

Suppose, however, that the sequence of the records according to key does not match arrival sequence, as could occur if you're reusing deleted records. What then?

Let's say that the remaining records, in arrival sequence, have sequence numbers 17, 12, 4, and 1. When the system tries to assign 4 to the first record (sequence number 17), it chokes with SQL state 23505 (A violation of the constraint imposed by a unique index or a unique constraint occurred) because there is already another row with a key value of 4.

In this case, you could update using a two-step process:

  1. Update the keys to an unused range of numbers.
  2. Renumber them, beginning with 1, as in the previous example.

Here are a couple of possibilities.

In this version, I add the number of active records in the file to the sequence numbers before re-sequencing them.

D RowCount        s             10u 0

D ReSeqUpd2       pr                  extpgm('RESEQUPD2')
D   ouStatus                     8a
D ReSeqUpd2       pi
D   ouStatus                     8a

D SqlEof          c                   const('02000')
D AllOK           c                   const('00-00000')
D UnexpectedError...
D                 c                   const('99-99999')

 /free
     *inlr = *on;
     ouStatus = AllOK;

     monitor;
        exec sql
             select count(*)
               into :RowCount
               from reseq;
        if RowCount <= *zero;
           return;
        endif;
        if SqlState > SqlEof;
           ouStatus = '10-' + SqlState;
        endif;
        if SqlState >= SqlEof;
           return;
        endif;

        exec sql
            update reseq as a
              set a.sequence = a.sequence + :RowCount;
        if SqlState > SqlEof;
           ouStatus = '20-' + SqlState;
           return;
        endif;

        exec sql
            update reseq as a
              set a.sequence =
                      (select count(b.sequence)
                         from reseq as b
                        where b.sequence <= a.sequence);
        if SqlState > SqlEof;
           ouStatus = '30-' + SqlState;
           return;
        endif;

     on-error;
        ouStatus = UnexpectedError;
     endmon;

     return;

After the first update, the rows have sequence numbers 21, 16, 8, and 5. After the second update, the sequence numbers are 4, 3, 2, and 1, of course.

Here's a similar version, built on the assumption that sequence numbers are always positive. In the first update, subtract the highest sequence number in use in order to convert the key values to numbers less than 1.

D MaxSequence     s              5p 0

D ReSeqUpd2       pr                  extpgm('RESEQUPD2')
D   ouStatus                     8a
D ReSeqUpd2       pi
D   ouStatus                     8a

D SqlEof          c                   const('02000')
D AllOK           c                   const('00-00000')
D UnexpectedError...
D                 c                   const('99-99999')

 /free
     *inlr = *on;
     ouStatus = AllOK;

     monitor;
        exec sql
             select max(Sequence)
               into :MaxSequence
               from reseq;
        if SqlState > SqlEof;
           ouStatus = '10-' + SqlState;
        endif;
        if SqlState >= SqlEof;
           return;
        endif;

        exec sql
            update reseq as a
              set a.sequence = a.sequence - :MaxSequence;
        if SqlState > SqlEof;
           ouStatus = '20-' + SqlState;
           return;
        endif;

        exec sql
            update reseq as a
              set a.sequence =
                      (select count(b.sequence)
                         from reseq as b
                        where b.sequence <= a.sequence);
        if SqlState > SqlEof;
           ouStatus = '30-' + SqlState;
           return;
        endif;

     on-error;
        ouStatus = UnexpectedError;
     endmon;

     return;

After the first update, the rows have key values of 0, -5, -13, and -16. After the second update, the key values are 4, 3, 2, and 1, as before.

Of course, if you reorganized the file, putting the records back into key sequence, the first example would work and you wouldn't need two updates.

RGZPFM FILE(RESEQ) KEYFILE(*FILE)

If UPDATE had an ORDER BY clause (but it doesn't, and I doubt it ever will), the first version would work, no matter the physical sequence of the records.

--Ted




                     Post this story to del.icio.us
               Post this story to Digg
    Post this story to Slashdot


Sponsored By
VISION SOLUTIONS

Leaders Have Vision...And Vision Has Leaders!

                                                - MIMIX High Availability for IBM i
                                                - iTERA High Availability for IBM i
                                                - Double-Take Availability for Windows
                                                - Double-Take RecoverNow for AIX
                                                - And Many Others!

Vision Solutions.
The Leader in IT Availability.

Learn more at
www.visionsolutions.com


Senior Technical Editor: Ted Holt
Technical Editor: Joe Hertvik
Contributing Technical Editors: Edwin Earley, Brian Kelly, Michael Sansoterra
Publisher and Advertising Director: Jenny Thomas
Advertising Sales Representative: Kim Reed
Contact the Editors: To contact anyone on the IT Jungle Team
Go to our contacts page and send us a message.

Sponsored Links

SEQUEL Software:  FREE Webinar. Learn how ABSTRACT can smooth software development. Jan. 19
Vision Solutions:  Leaders Have Vision...And Vision Has Leaders! FREE White Papers!
Bytware:  Try StandGuard Network Security FREE for 30 days


 

IT Jungle Store Top Book Picks

BACK IN STOCK: Easy Steps to Internet Programming for System i: List Price, $49.95

The iSeries Express Web Implementer's Guide: List Price, $49.95
The iSeries Pocket Database Guide: List Price, $59
The iSeries Pocket SQL Guide: List Price, $59
The iSeries Pocket WebFacing Primer: List Price, $39
Migrating to WebSphere Express for iSeries: List Price, $49
Getting Started with WebSphere Express for iSeries: List Price, $49
The All-Everything Operating System: List Price, $35
The Best Joomla! Tutorial Ever!: List Price, $19.95


 
The Four Hundred
The Carrot: i5/OS V5R4 Gets Execution Stay Until May

The Stick: IBM Jacks Up i5/OS V5R4 Prices

In the Best Interests of IBM i

As I See It: Return Of The Swami

Some Tweaks and Services for the Power Systems Platform

Four Hundred Stuff
Oracle Drops MySQL Support for IBM i

ASNA Splits from BluePhoenix

IBM i Vendors to Watch in 2011

Oracle Says JDE 'Blue Stack' Withdrawal No Big Deal

Linoma Adds Function to Multi-Tool

Four Hundred Monitor
Four Hundred Monitor's
Full iSeries Events Calendar

System i PTF Guide
September 25, 2010: Volume 12, Number 39

September 18, 2010: Volume 12, Number 38

September 11, 2010: Volume 12, Number 37

September 4, 2010: Volume 12, Number 36

August 28, 2010: Volume 12, Number 35

August 21, 2010: Volume 12, Number 34

TPM at The Register
Tech giants score record patent stash

Cisco comes out of switch closet with Catalyst

US job market still limp

IT sales beat expectations in 2010

NASA taps Unisys for flight sim mission

Amazon expands cloud services support

Nvidia forges ARM chip for PCs and servers

Fujitsu aims Sparc64 supers beyond Japan

Qualcomm gobbles Atheros, arms self for coming tablet wars

Ex-IBM channel marketeers turn hired guns

Reseller's VAR two-step lands Oz upside

January 4, 2011: DRAM prices plunging into 2011

THIS ISSUE SPONSORED BY:

Bytware
Vision Solutions
System i Developer


Printer Friendly Version


TABLE OF CONTENTS
Implementing Binary Trees in RPG

Closing the Gaps

Admin Alert: Basic i/OS Error Monitoring and Response, Part 2

Four Hundred Guru

BACK ISSUES




 
Subscription Information:
You can unsubscribe, change your email address, or sign up for any of IT Jungle's free e-newsletters through our Web site at http://www.itjungle.com/sub/subscribe.html.

Copyright © 1996-2011 Guild Companies, Inc. All Rights Reserved.
Guild Companies, Inc., 50 Park Terrace East, Suite 8F, New York, NY 10034

Privacy Statement