Home

Resources
 

Creating a user defined function to convert legacy dates

I showed you how to convert a DECIMAL(7,0) date value into an AS/400 Date field using SQL. In this article, I will take that one step further and create a user-defined function, (UDF), that will return a date from the legacy date field. The advantage of a UDF is that it simplifies your client side SQL and encapsulates the date conversion logic on the server.

First, lets review the situation. The client has a table which contains a log number and a DECIMAL(7,0) field that contains a representation of a date. The date is encoded as CYYMMDD where C is 0 for 1900 and 1 for 2000. The following SQL Statements will create the table in a library called WEBOE and will insert the test data into the tables.

CREATE TABLE weboe.h1t2
	(log DECIMAL(5,0),
	 ymd DECIMAL(7,0));

INSERT INTO weboe.h1t2 VALUES (1096,821231);
INSERT INTO weboe.h1t2 VALUES (1461,831231);
INSERT INTO weboe.h1t2 VALUES (2192,851231);
INSERT INTO weboe.h1t2 VALUES (7305,991231);
INSERT INTO weboe.h1t2 VALUES (7306,1000101);
INSERT INTO weboe.h1t2 VALUES (10228,1080101);

The formula for creating a date from the YMD field value is the following SQL expression:

DATE(
	SUBSTR(CHAR(19000000 + YMD),5,2) ||/||
	SUBSTR(CHAR(19000000 + YMD),7,2) ||/||
	SUBSTR(CHAR(19000000 + YMD),1,4)
	)

Again, putting this in an SQL statement is a real bear, especially if you have several dates that you want to convert in a single statement or if you want to do date manipulations with the resultant data. The following UDF, written in PSM language, can be executed on a V4R5/V5R1 system to create a user-defined function that will convert the legacy date into an SQL date. Hint, SQLThing Enterprise Edition has a fantastic color function syntax editor that you could use to enter and compile this code.

CREATE FUNCTION WEBOE.CONVDATE
	(I_YMD DECIMAL(7,0))
  RETURNS DATE
  LANGUAGE SQL
BEGIN
  DECLARE F_OUTPUT DATE;
  DECLARE F_TEST INTEGER;
  DECLARE CONTINUE HANDLER FOR SQLEXCEPTION
  SET F_TEST=1;
  SET F_TEST=0;
  SET F_OUTPUT = DATE(
          SUBSTR(CHAR(19000000 + I_YMD),5,2) ||'/'||
          SUBSTR(CHAR(19000000 + I_YMD),7,2) ||'/'||
          SUBSTR(CHAR(19000000 + I_YMD),1,4)
        );
  IF F_TEST=0 THEN
       RETURN F_OUTPUT;
  ELSE
       RETURN NULL;
  END IF;
END

This function takes as input a DECIMAL(7,0) field. As output, it returns an SQL DATE value. Note that I have placed a continue handler to grab any SQL exception and set the variable F_TEST equal to 1. If I have bum values in the input to the function, the exception handler will cause F_TEST to be set to 1 and execution of the UDF will continue. On the line after the date conversion, I look at the value of F_TEST. If F_TEST is 0, then the date conversion was successful and I return the value of the F_OUTPUT field, (which contains the date). If the conversion was unsuccessful, I return a NULL. In this manner, my function will execute correctly even if the input data is bad and not cause an exception.

To put the function on your machine, you can execute the above code in STRSQL, or if you have a copy of SQLThing Enterprise Edition, you can use the Procedure/Function editor to enter the code and create the function. Once the function is created on your AS/400, the following SQL statement will work against your AS/400.

SELECT LOG, YMD, WEBOE.CONVDATE(YMD) 
	FROM WEBOE.H1T2;

Notice that I qualified the name of the user defined function with the library where it lives. This is so that SQL can find the user defined function. To avoid having to qualify my user-defined function, I could execute the following statement prior to using my new user defined function:

SET PATH=WEBOE;

The above statement causes the AS/400 to search for any user defined functions in the WEBOE library. Note that the argument to PATH can be a list of libraries, so the following would be valid:

SET PATH=HD1100PD, WEBOE;

The above statement causes the AS/400 to search for user-defined functions first in the HD1100PD library, and then in the WEBOE library.

Executing the SQL statement above against the test table will cause the following output to appear:

 LOG

 YMD

 EXPR0003

 1096

 821231

 12/31/1982

7305

991231

12/31/1999

7306

1000101

01/01/2000

10228

1080101

01/01/2008

2192

851231

12/31/1985

1461

831231

12/31/1983

Now that I have the user-defined function, my SQL statements can be a little easier to read and I can manipulate the numeric date fields quite easily. Here is an example statement where I do a number of manipulations against the output of the function:

SELECT log, ymd,convdate(ymd) AS DATE,
	dayofweek(convdate(ymd)) AS DAYOFWEEK,
	quarter(convdate(ymd)) AS QUARTER,
	week(convdate(ymd)) AS WEEK
  FROM weboe.h1t2

The output of the above statement should look like this:

 LOG

 YMD

 DATE

 DAYOFWEEK

 QUARTER

 WEEK

 1096

821231

12/31/1982

6

4

53

7305

991231

12/31/1999

6

4

53

7306

1000101

01/01/2000

7

1

1

 10228

 1080101

 01/01/2008

 3

 1

 1

2192

851231

12/31/1985

3

4

53

1461

831231

12/31/1983

7

4

53

User-defined functions can be great for simplifying statements on placing business logic on the server.

-Howard