As RPG programmers, we have become very comfortable with character, zoned, and packed decimal data types. Occasionally, when dealing with APIs or subprocedures, we’ve been forced to dabble with binary numbers or variable length strings. More recently some of us have started taking advantage of the strengths of the date, time, and timestamp data types supported in RPG IV. And just when we think we’ve got it all covered, we find out that DB2 supports even more data types.
DB2 supports data types that are seldom used by iSeries programmers. However, since C or Java programmers may create tables (or files) on the iSeries, we need to know how to interact with these data types.
The following tables list the data types that can be used in DB2 on the iSeries.
Numeric Data Types
Min Value
Max Value
Bytes of Storage Used
Small Integer
-32,768
32,767
2
Integer
-2,147,483,648
2,147,483,647
4
Big Integer
-9,223,372,036,854,775,808
9,223,372,036,854,775,807
8
Decimal
-1031 + 1
1031 - 1
Up to 16
Numeric
-1031 + 1
1031 - 1
Up to 31
Float(Single Precision)
1.17549436 x 10-38
3.40282356 x 1038
4
Float(Double Precision)
2.2250738585072014 × 10-308
1.7976931348623158 x 10308
8
String Data Types
Description
Max Length
Char
Fixed Length Character Data
32,766
VarChar
Variable Length Character Data
32,740
CLOB
Character Large Object String
15,728,640
Graphic
Fixed Length Graphic String
16,383
VarGraphic
Variable Length Graphic String
16,370
DBCLOB
Double Byte Character Large Object String
7,864,320
BLOB
Binary Large Object String
15,728,640
Date/Time Data Types
Contents
Limits
Bytes of Storage Used
Date
3 part value: Year, Month and Day
If the date format *JUL, *MDY, *DMY, or *YMD is used, the year part of the value can only represent dates in the range 1940 through 2039.
4
Time
3 part value: Hour, Minutes and Seconds
0
3
TimeStamp
7 part value: Year, Month, Day; Hours, Minutes, Seconds, Microseconds
0
10
Now that we know just how much we don't know, let's look at how to define these data types in RPG and how to convert to and from these data types using SQL scalar functions.
DEFINING SQL DATA TYPES IN RPG
Let me start by saying that the SQL precompiler does a lot of the hard work for you. When you use embedded SQL to put data into your application, you must define "host variables" to contain the values selected in your SQL statement. When using native I/O, coding an F-spec adds the fields and their definitions into the program, during the compile process. Embedded SQL does not require an F-spec. Instead, host variables are defined in D-specs, like any other variable in RPG. Host variables can be defined as stand-alone fields, data structures, externally described data structures or multiple occurrence data structures.
In the example below, a single host variable has been defined. When the SQL statement runs, the number of records in the QADBXREF file will be placed into the variable RecordCount. In this case, RecordCount is defined as a packed decimal value with a precision of 9,0.
.....DName+++++++++++ETDsFrom+++To/L+++IDc.Keywords
D RecordCount S 9 0
C/Exec SQL
C+ Select Count(*) into :RecordCount from QADBXREF
C/End-Exec
Now let's make a change. Notice that the RecordCount variable is now defined as a zoned decimal value with a precision of 7,0. This code will also work just fine.
.....DName+++++++++++ETDsFrom+++To/L+++IDc.Keywords
D RecordCount S 7S 0
C/Exec SQL
C+ Select Count(*) into :RecordCount from QADBXREF
C/End-Exec
Now the RecordCount variable is defined as a four-byte Integer. This code will also work.
.....DName+++++++++++ETDsFrom+++To/L+++IDc.Keywords
D RecordCount S 5I 0
C/Exec SQL
C+ Select Count(*) into :RecordCount from QADBXREF
C/End-Exec
The point that I am trying to make is that if the data types are not the same, the program will work to convert the value correctly, if possible. The data types do not have to be the same, but they do need to be compatible. If the value of one data type can be assigned to another without the use of a scalar function, the data types are compatible. For example, a small integer value can be assigned to a decimal variable, a character value can be assigned to a character large object, and a correctly formatted character value can be assigned to a date variable. Just like in RPG, you can add a zoned decimal to an integer and store the results in a packed decimal field. You don't have to worry about the differences; RPG will handle all of the data type conversions necessary. So if a column in your table is defined as numeric, but you define it as an integer in RPG, the conversion will be handled automatically. The most important thing to watch for is that you keep data from being truncated as it moves from one data type to another.
The source code listed below shows a sample RPG definition for each SQL data type. Care should be taken not to exceed the maximum length, as shown in the table above, or change the lengths of the integer or float data types. Large objects require the SQLTYPE keyword, which is processed by the SQL precompiler.
.....DName+++++++++++ETDsFrom+++To/L+++IDc.Keywords
* Numeric Definitions
D SmallInteger S 5I 0
D SmallInteger S 4B 0
D Integer S 10I 0
D Integer S 9B 0
D BigInteger S 20I 0
D Decimal S 31P 9
D Numeric S 31S 9
D Float_Single S 4F
D Float_Double S 8F
* Character Definitions
D Char S 32766A
D VarChar S 32740A Varying
* Graphic Data Definitions
D Graphic S 16383G
D VarGraphic S 16370G Varying
* Large Object Definitions
D CLOB S SQLTYPE(CLOB:500)
D DBCLOB S SQLTYPE(DBCLOB:500)
D BLOB S SQLTYPE(BLOB:500)
* Date/Time Definitions
D Date S D
D Time S T
D TimeStamp S Z
For performance reasons, it makes sense to avoid unnecessary data type conversions, but the system will convert compatible data types nonetheless.
CHANGING BETWEEN DATA TYPES IN SQL
It seems as if programmers spend a lot of their time changing data from one type to another. A value stored as a number is converted to a date, an invoice amount is converted to a character string, so it can be inserted into a body of text, and on and on. SQL has built-in functions to accomplish these tasks as well. These functions allow you to control the length, precision, and data type of your results. The rest of this article examines the use of scalar functions to convert between data types. However, another option is available within SQL. The CAST expression lets you perform the same data type conversions as individual scalar functions. Once you master the scalar functions, you can decide which you prefer.
CONVERTING TO CHARACTER DATA
The first method of converting data to the character data type is the CHAR() function. The results of the CHAR() function depend on the data type being converted.
The CHAR() function will convert the following:
Character data to character
Char (character expression, length)
Integer data to character
Char (integer expression)
Decimal data to character
Char (decimal expression, decimal character)
Float data to character
Char (float expression, decimal character)
Date/Time data to character
Char (date time expression, format)
The table below shows the resulting length of the Char() function based on the source data type.
Source
Source
Data Type
Comments
Length of
Result
Character
The result is a character string of the length specified
in the second argument.If the second
argument is not specified, the resulting string is the same length as the
source string.
Small Integer
Fixed length.
Preceding minus sign if negative.
Left justified.
No leading zeros.
Padded on the right with blanks
6
Integer
11
Big Integer
20
Decimal
Variable Length
Preceding minus sign if negative.
Left justified.
No leading zeros.
If the value is positive, there will be one trailing
blank.
The decimal character can be a period or a comma and is
specified on the second argument.
Precision of source
value
+ 2
Float
Fixed length.
Preceding minus sign if negative.
If the value is zero,
the returned string is 0E0.
The smallest number of
digits/characters possible is
used to
represent the value.
Padded on the right
with blanks.
24
Date
The format and separator are determined by the second
argument of the function.If no format
is specified, the value of the DATFMT and
DATSEP parameters is used.
ISO, USA, EUR,or JIS date format
10
YMD, MDY, or DMY date
format
6
Time
The format and separator are determined by the second
argument of the function.If no format
is specified, the value of the TIMFMT and
TIMSEP parameters is used.
8
TimeStamp
The second argument is not allowed when converting this
data type.
26
The table below shows some samples of the CHAR() function.
Source
Source
Data Type
Source Data
CHAR() statement
Result
Character
Name = 'Dr. Suess'
Char(Name,5)
'Dr. S'
Char('I like ' +
Name,20)
'I like Dr. Suessbbbb'
Small Integer
Sm_Int = 45
Char(Sm_Int)
'45bbbb'
Integer
Int = -654321
Char(Int)
'-654321bbbb'
Big Integer
Big_Int = 32468465654005
Char(Big_Int-5)
'32468465654000bbbbbb'
Decimal
Num1 = 36.68
Char(Num1)
'36.68b'
Num2 = -1254.996
Char(Num2,',')
'-1254,996'
Char(10000.00-99865)
'135.00bbb'
Float
Double =
-987.654321E-35
Char(Double)
'-9.8765432100000002E-33
'
Date
InvDate = 2003-05-22
Char(InvDate, USA)
'05/22/2003'
Char(InvDate, YMD)
'03/05/22'
Time
ChgTime = 09.25.01
Char(ChgTime,USA)
'9:25 AMb'
TimeStamp
Char(InvDate+ChgTime)
'2003-05-22-09.25.01.000000'
Another function for converting to character data is the DIGITS() function. The DIGITS() function works with integer and decimal data types only. The value returned is an absolute value that is right-justified with leading zeros and no decimal separator. This function works well when you are formatting a "flat file" for export or when you want to append a sequence number to a character value. There is no equivalent CAST expression for the DIGITS() function. The following table shows the length and sample uses of the DIGITS() function.
Source
Source
Data Type
Source Data
DIGITS() statement
Length
Result
Small Integer
Sm_Int = 45
Digits(Sm_Int)
5
'00045'
Integer
Int = -654321
Digits(Int)
10
'0000654321'
Big Integer
Big_Int = 32468465654005
Digits(Big_Int-5)
19
'0000032468465654000'
Decimal
Num1 = 36.68
Digits(Num1)
Precision
of Source value
'3668'
Num2 = -1254.996
Digits(Num2)
'1254996'
Digits(10000.00-99865)
'0013500'
CONVERTING TO DATE/TIME DATA TYPES
The DATE() function returns a date from a value. The value supplied to the DATE() function can be represented in a number of ways. The value can be a timestamp, a date, a positive number, or a string. If the value supplied is a timestamp, the returned value is the date portion of the timestamp. If the supplied value is a date, then that date is returned. If the value supplied is a number, it must represent the number of days after January 1, 0001. If the value supplied is a string, it must be a valid date string or a seven-character numeric string in the form yyyynnn; where yyyy is the year and nnn is the number of days (1-366) since the beginning of the year.
DATE() EXAMPLES
Constants
Constants
Format
Date() statement
Result
Chg_Date = '2004-11-25'
Rec_Date = '2003-05-22-09.25.01.000000'
Date
Date(Chg_Date)
2004-11-25
TimeStamp
Date(Rec_Date)
2003-05-22
Numeric
Date(731885)
2004-10-31
USA
Date('12/05/2001')
2001-12-05
ISO
Date('2004-11-01')
2004-11-01
EUR
Date('22.09.1998')
1998-09-22
yyyynnn
Date('2000214')
2000-08-01
The TIME() function returns a Time value from a value. The value supplied to the TIME() function can also be represented in a number of ways. The value can be a TimeStamp, Time, or string. If the value supplied is TimeStamp, the returned value is the time portion of TimeStamp. If the supplied value is a time, that time is returned. If the value supplied is a character string, that string must be a valid representation of a time value.
TIME() Examples
Constants
Constants
Format
Time() statement
Result
Chg_Date = '2004-11-25'
Chg_Time= '13.22.05'
Rec_Date = '2003-05-22-09.25.01.000000'
Time
Time(Chg_Time)
13.22.05
TimeStamp
Time(Rec_Date)
9.25.01
USA
Time('01:05 PM')
13.05.00
ISO
Time('18.11.59')
18.11.59
EUR
Time('18.11.58')
18.11.58
JIS
Time('16:42:46')
16.42.46
The TIMESTAMP() function returns a timestamp from a value. The TIMESTAMP function can accept one or two arguments. If only one argument is specified, it must be a timestamp or a 14-character representation of a timestamp. The format for the 14-character string is yyyyMMddhhmmss, where yyyy is for the year, MM is for the month, dd is for the day, hh is for the hour, mm is for the minute, and ss is for the number of seconds. If two arguments are specified, the first value must be a date or a character representation of a date value and the second value must be a date or a character representation of a time value.
TIMESTAMP() Examples
Constants
Constants
Format
Date() statement
Result
Chg_Date = '2004-11-25'
Chg_Time= '13.22.05'
Rec_Date =
'2003-05-22-09.25.01.000000'
TimeStamp
TimeStamp(Rec_Date)
2003-05-22-09.25.01.000000
Character
TimeStamp('20040522135204')
2004-05-22-13.52.04.000000
TimeStamp(Chg_Date,Chg_Time)
2004-11-25-13.22.05.000000
TimeStamp('10/15/1975',
'08:55:01')
1975-10-15-08.55.01.000000
CONVERTING TO INTEGER DATA TYPES
To convert to an Integer data type use one of the following expressions:
SmallInt()
Integer() or Int()
BigInt()
The syntax for these functions is the same. There is only one argument for these functions. The argument can be a number, a numeric expression, or a character-string representation of an integer, decimal, or float data type. The table below shows some examples of these functions.
Constants
Constants
Function
Result
Total = 456.254
Count = 15
SmallInt(1235.564)
1235
Int(Total/Count)
30
BigInt('89465411')
89465411
Integer('45323.55')
45323
CONVERTING TO NUMERIC DATA TYPES
To convert data to a numeric format, use the following functions:
Decimal() or Dec()
Zoned()
For these functions, the data type of the first argument determines the rest of the syntax. The first argument can be a number, a numeric expression, or a character-string representation of an integer, decimal, or float data type.
If the first argument is numeric:
The second argument is an integer value for the desired precision for the result.
The third argument is an integer value for the desired scale for the result.
If the first argument is a character string:
The second argument is an integer value for the desired precision for the result.
The third argument is an integer value for the desired scale for the result.
The fourth argument is the character that is to be used as the decimal separator in the first argument.
The value of the precision argument is from 1 to 31. If no precision is specified, the precision is defaulted to the values listed below, based on the data type of the first argument.
Data Type
Data Type
Default Precision
Floating Point
Decimal
Numeric
15
Big Integer
19
Integer
11
Small Integer
5
The value of the scale argument is from zero to the precision specified in the second argument.
The value of the separator argument is either a comma (,) or a period (.).
The table below shows some examples of the ZONED() and DECIMAL() functions.
Constants
Constants
Function
Result
Total = 456.254
Count = 15
Decimal(135,9,3)
135.000
Zoned('1254.33',8,4)
1254.0000
Decimal(Total/Count,9,2)
30.42
Zoned('8912354,79',9,2,',')
8912354,79
CONVERTING TO FLOAT DATA TYPES
To convert data to a float data type, use the following functions:
Double() or Double_Precision()
Float()
Real()
The syntax for these functions is the same. There is only one argument for these functions. The argument can be a number, a numeric expression, or a character-string representation of an integer, decimal, or float data type. The table below shows some examples of the functions.
Constants
Constants
Function
Result
Total = 456.254
Count = 15
Real(1235.564)
1.2355640000E+03
Real(Total/Count)
3.0416933333E+01
Real('89465411')
8.9465411000E+07
Real('45323.55')
4.5323000000E+04
Real('9.879822E+04')
9.8798220000E+04
YOU ARE IN CONTROL
These functions allow you to have complete control over your data and data types. These functions can also be nested within other functions. When this approach is combined with the creation of a view, your data conversions can be defined one time for all programs or users. Another use for these functions is when you need to duplicate an existing formula coded within another language. By specifying the precision and scale of your operands, you can control the resulting value of a formula. These functions require frequent use before they become second nature to you. In the meantime, refer to your reference manuals frequently and don't be afraid to experiment with new functions.
Raymond Everhart has over 18 years of IT experience with IBM midrange computers. He was a consultant, programmer, and educator for an IBM premier business partner in Upstate New York for 10 years, before relocating to the Dallas/Ft. Worth area in 1998. Since then, Raymond has been helping local companies implement new technologies with his consulting, programming and mentoring services. E-mail: reverhart@itjungle.com
Sponsored By COMMON
COMMON Spring 2004 IT Education Conference & Expo
San Antonio, Texas
May 2-6, 2004
Conference activities will take place in the Marriott River Walk and the Henry B. Gonzalez Convention Center.
Click here for online registration and hotel reservations.