Avatar of Theo Kouwenhoven
Theo Kouwenhoven
Flag for Netherlands asked on

SQL null values in RPG

Hi Experts,

I have some SQLRPGLE problems with reading a tabel (with null capable fields)
The program reads a record in a DS , change 2 fields and write it to a remote (identical) table.

But I have to add a null "check field" per field
exec sql fetch next from cIMPH INTO
 :DS_REFERENCE       :ISNUL1,          
 :DS_CONTEXT         :ISNUL2,          
 :DS_OBJECT_TYPE     :ISNUL3;

In this example it's not a problem, but I need to do this for a file with round 100 fields.
So I prefer to use the SQL

exec sql fetch next from cIMPH INTO :DS;

On top of that, if I use the null-check field, the original field contains a space or a zero.
the remote table expect null values.

How can I solve this?
IBM System iSQL* RPGLE

Avatar of undefined
Last Comment
Theo Kouwenhoven

8/22/2022 - Mon
ASKER CERTIFIED SOLUTION
Gary Patterson, CISSP

THIS SOLUTION ONLY AVAILABLE TO MEMBERS.
View this solution by signing up for a free trial.
Members can start a 7-Day free trial and enjoy unlimited access to the platform.
See Pricing Options
Start Free Trial
GET A PERSONALIZED SOLUTION
Ask your own question & get feedback from real experts
Find out why thousands trust the EE community with their toughest problems.
Theo Kouwenhoven

ASKER
Hi Gary,

I figured that out allready, but then I need to make an insert statment with 100 fields and 100 values (+ nullind),
that will become unreadable and unmaintainable  

What if I read the file using RPG with ALWNULL(*USRCTL)

(until now I avoid using null capability, because of this problems)
Theo Kouwenhoven

ASKER
Hi Gary,

After some trial & error, its working (until now)

VALUES (:host-var1:nullInds(1), :host-var2:nullInds(2), ...) is not working, compile error on use of array index  :-(
But VALUES (:dataDS:nullInds) is functioning as long as dataDS is not qualified, so writeout per field is not required :-)
Gary Patterson, CISSP

Good solution.  You can also get around the array index issue by overlaying the NullInds array with a DS of named elements, then using the meaningful names in your SQL statement.  This is particularly useful if the SELECT DS and INSERT format aren't identical, and you are only dealing with a subset of columns.

        dcl-ds ids;
            meaningfulName1Null int(5);
            meaningfulName2Null int(5);
            meaningfulName3Null int(5);
            meaningfulName4Null int(5);
            meaningfulName5Null int(5);
            NullInds int(5) dim(5) pos(1);
         End-Ds;

Then in SQL:

VALUES (:meaningfulName1:meaningfulName1Null, :meaningfulName2:meaningfulName2Null, ...)

And as for writing maintainable SQL, use this format, with one variable/null indicator pair per source line:

VALUES (
:meaningfulName1:meaningfulName1Null,
:meaningfulName2:meaningfulName2Null,
...
)
Experts Exchange has (a) saved my job multiple times, (b) saved me hours, days, and even weeks of work, and often (c) makes me look like a superhero! This place is MAGIC!
Walt Forbes
Theo Kouwenhoven

ASKER
Hi Gary,

Now the next problem:
Nullind in SQL is working fine.
The nullind in RPG is working also (I assume)
FMYIMPH    IF   E           K DISK    ALIAS                    
DIMPH             DS                  LIKEREC(IMPH_00001)      
D                                     NULLIND(IMPHNULL)        
DIMPHNULL         DS                  LIKEREC(IMPH_00001:*NULL)

Open in new window

IMPHNULL is containing an serie of qualified, named indicator-fields, where *Off is notNull and *On is Null....

SQL expect an array of integer(5) fields with indication 0 or -1 as nullind.

I have to read the record from the local file (with RPG) and have to write it to a remote DB with SQL but the nullind fields are not compatible.
(not investigated yet) but I don't think that I can read with SQL from the local DB and write to an remote server in the same program?
Gary Patterson, CISSP

In the past, I've always segregated operations like this in separate programs.  If both systems are IBM I db2, you can access both the local and remote db in the same program.  Pre v7r1 you have to explicitly CONNECT to each system each time you switch target DBs, but you dont lose existing connections when you do that.  In v7r1, you can use 3 part naming and skip the CONNECT TO step.  Havent tested this with Ardgate running to a non IBM I remote db, though.
Gary Patterson, CISSP

I assume you are constructing SQL dynamically.  If so, you could just use a set of IF blocks to test each null indicator and append the special value NULL to your SQL INSERT string in place of a value when the null indicator is on.  This enables you to avoid the whole null indicator issue on the INSERT completely.
⚡ FREE TRIAL OFFER
Try out a week of full access for free.
Find out why thousands trust the EE community with their toughest problems.
Theo Kouwenhoven

ASKER
Hi Gary,

"I assume you are constructing SQL dynamically."

Wrong assumption :-)
I will write the complete records 1:1 from the local table to the remote-DB.
Otherwise I have to dynamically generate the field names (up to 100 names) and the values.
Theo Kouwenhoven

ASKER
Found a workaround :-)

DIMPH             DS                  LIKEREC(IMPH_00001)      
D                                     NULLIND(iNull)         
DiNull            Ds                  LIKEREC(IMPH_00001:*Null)
                                                               
DoNull            S              5I 0 dim(100)                 

     clear oNull;                       
     For idx = 1 to %len(iNull);      
       If %subst(iNull:idx:1) = '1';  
         oNull(idx) = -1;               
       endif;                           
     endfor;                            

Open in new window

array oNull can be used on the SQL insert :-)
It's not very nice, but it will work.
Peter Price

If you dont like the NULL VALUES, you coould actually try modifying your SQL select statement to include COALESCE. For example

Select Cast(COALESCE(b.Account_Name, a.Customer_Name, '*UNKNOWN) as Character(128)) as Resolved_Name from CUSTOMER_TABLE as a LEFT OUTER JOIN ACCOUNT_Table as b On a.CUST_Id = b.Cust_Id
This is the best money I have ever spent. I cannot not tell you how many times these folks have saved my bacon. I learn so much from the contributors.
rwheeler23
Gary Patterson, CISSP

@P_S_PRICE:  Unfortunately, that's not even remotely related to this problem.  

If you'll review the entire thread, you'll see that the poster is reading from a null-capable table on one system, and writing to a null-capable table on another system, and needs to set the null indicator correctly (and if I recall correctly from another thread, the remote DB may not be IBM i DB2, so null indicators may require a different format).
Theo Kouwenhoven

ASKER
unfortunately, the remote DB doesn't accept the SQL400 way of presenting null-values (doesn't surprise me its microsoft :-)

So I dynamically assign the fields and values to write only not Null fields.  
The field default on the remote site will do the rest .
Theo Kouwenhoven

ASKER
Answer point me to the complete solution.
⚡ FREE TRIAL OFFER
Try out a week of full access for free.
Find out why thousands trust the EE community with their toughest problems.