The idea for this post came from Jonathan Heinz who brought to my attention the REPEAT SQL scalar function in a comment to a post. I have to admit I had not heard of it so this post is examples of how I played with it to become familiar with its use.
Being a scalar function it can be used within a Select, Set, or Values statement. Its syntax is:
REPEAT('characters-to-repeat', number-of-times-to-repeat) |
I started playing with it in ACS's Run SQL Scripts, using a Values statement:
VALUES REPEAT('test', 3) |
In the above I want to repeat the word 'test' three times. When executed the result is:
00001 ------------ testtesttest |
If character or numeric data is used the result is variable length character format, VARCHAR.
I can do the same with a number:
VALUES REPEAT (123, 5) |
Here I am repeating the number 123 file times.
00001 --------------- 123123123123123 |
Even though the result looks like a number, it is VARCHAR.
How could I use this in a RPG program?
01 **free 02 ctl-opt option(*srcstmt) ; 03 dcl-s String char(31) ; 04 dcl-s Number packed(15 : 5) ; 05 exec sql SET :String = REPEAT('< test >', 3) ; 06 dsply ('1. ' + String) ; 07 exec sql SET :String = REPEAT('< test >', 100) ; 08 dsply ('2. ' + String) ; 09 exec sql SET :String = REPEAT(123, 3) ; 10 dsply ('3. ' + String) ; 11 Number = %dec(String : 15 : 5) ; 12 dsply ('4. ' + %char(Number)) ; |
Line 1: If it is written in 2024 it has to be modern RPG.
Line 2: I add this control option to all my programs. It makes problem diagnosis so much simpler.
Lines 3 and 4: Definition of the variables I will be using in this program.
Line 3: I am using the SQL Set statement to move the result of the Repeat into the variable called String. I am repeating the string '< test >' three times.
Line 4: I display the results:
DSPLY 1. < test >< test >< test > |
Which shows the string was repeated three times.
Line 7: What happens if I repeat more times than it will fit in the RPG variable? Here I am repeating 100 times.
Line 8: The result looks like:
DSPLY 2. < test >< test >< test >< test |
The repeat pattern does not fit in the variable String. I only get 3.75 of the repeat pattern.
Line 9: Here I am repeating the number 123 three times.
Line 10: Remember the result is not numeric, it is VARCHAR:
DSPLY 3. 123123123 |
Line 11: I am using the Convert to Decimal built in function, %DEC, to convert the VARCHAR to decimal in the packed variable Number.
Line 12: Now the result is a number:
DSPLY 4. 123123123.00000 |
In the next example program I want to insert the default value into all the columns of a SQL DDL Table. First I need a table:
01 CREATE TABLE QTEMP.TESTTABLE ( 02 ID_COLUMN SMALLINT GENERATED ALWAYS AS IDENTITY, 03 COLUMN1A VARCHAR(10) DEFAULT 'COL 1', 04 COLUMN1B VARCHAR(10), 05 COLUMN2A DECIMAL(3,0) DEFAULT -1, 06 COLUMN2B DECIMAL(3,0), 07 COLUMN3A DATE DEFAULT '01/01/1900', 08 COLUMN3B DATE, 09 COLUMN4A TIMESTAMP DEFAULT '1900-09-24-12.17.34.123456', 10 COLUMN4B TIMESTAMP) |
The default for the columns where I have not given a default value will be null.
01 **free 02 ctl-opt option(*nodebugio : *srcstmt) ; 03 dcl-s SQL varchar(200) ; 04 dcl-s ColumnValues varchar(100) ; 05 exec sql SET :ColumnValues = REPEAT('DEFAULT,', 9) ; 06 %subst(ColumnValues : %len(ColumnValues) : 1) = '' ; 07 SQL = 'INSERT INTO QTEMP.TESTTABLE VALUES(' + 08 ColumnValues + ')' ; 09 exec sql EXECUTE IMMEDIATE :SQL ; |
Line 5: I use the Set SQL statement and the Repeat scalar function to create a repeat for nine times for the word default followed by a comma. I repeat for nine times as the Table has nine columns.
> EVAL ColumnValues COLUMNVALUES = ....5...10...15...20...25...30...35...40...45...50...55...60 1 'DEFAULT,DEFAULT,DEFAULT,DEFAULT,DEFAULT,DEFAULT,DEFAULT,DEFA' 61 'ULT,DEFAULT, ' |
The string ends with a comma. I need to remove that.
Line 6: I replace the last character in the variable using a Substring built in function, BiF. I am using the Length BiF, %LEN, to get the length of the string within the variable, and replace the last character with null.
> EVAL ColumnValues COLUMNVALUES = ....5...10...15...20...25...30...35...40...45...50...55...60 1 'DEFAULT,DEFAULT,DEFAULT,DEFAULT,DEFAULT,DEFAULT,DEFAULT,DEFA' 61 'ULT,DEFAULT ' |
Lines 7 and 8: I can build my SQL Insert statement, and use the ColumnValues variable for the values of the columns:
> EVAL SQL SQL = ....5...10...15...20...25...30...35...40...45...50...55...60 1 'INSERT INTO QTEMP.TESTTABLE VALUES(DEFAULT,DEFAULT,DEFAULT,D' 61 'EFAULT,DEFAULT,DEFAULT,DEFAULT,DEFAULT,DEFAULT ) ' 121 ' ' 181 ' ' |
Line 9: I now use the SQL EXECUTE IMMEDIATE statement to execute the Insert statement in the variable SQL.
The results of the Insert look like:
ID_COLUMN --------- 1 COLUMN1A COLUMN1B --------- -------- COL 1 <NULL> COLUMN2A COLUMN2B -------- -------- -1 <NULL> COLUMN3A COLUMN3B ---------- -------- 1900-01-01 <NULL> COLUMN4A COLUMN4B -------------------------- -------- 1900-09-24-12.17.34.123456 <NULL> |
And finally I am going to show Jonathan's SQL statement with the Replace, it was to obscure an user's email address:
SELECT EMAIL_ADDRESS, SUBSTR( EMAIL_ADDRESS, 1, 1) || repeat('x', LOCATE_IN_STRING( EMAIL_ADDRESS, '@') -2) || SUBSTR( EMAIL_ADDRESS, LOCATE_IN_STRING(EMAIL_ADDRESS, '@')) FROM TESTFILE; |
Which gives me:
EMAIL_ADDRESS 00002 ---------------- ---------------- SIMON@RPGPGM.COM Sxxxx@RPGPGM.COM |
Thank you Jonathan for the feedback, and the opportunity to play with something new to me.
You can learn more about SQL's Replace scalar function from the IBM website here.
This article was written for IBM i 7.5, and should work for some earlier releases too.
No comments:
Post a Comment
To prevent "comment spam" all comments are moderated.
Learn about this website's comments policy here.
Some people have reported that they cannot post a comment using certain computers and browsers. If this is you feel free to use the Contact Form to send me the comment and I will post it for you, please include the title of the post so I know which one to post the comment to.