
MainframeSupports tip week 25/2009:
Nowadays it has become fashion to use a timestamp column as unique key. One of the problems by
using this aproach is that two inserts on the same table may be using the same timestamp. Another
irritating detail is that you cannot use INSERT INTO ... SELECT * FROM ... on such tables if
you want to generate new unique timestamps with CURRENT TIMESTAMP. If your installation is
running DB2 version 7 or later then the function GENERATE_UNIQUE is able to help you.
First of all you can find out whether GENERATE_UNIQUE works on your DB2. It is very easily
done using a:
SELECT CHAR(TIMESTAMP(GENERATE_UNIQUE()))
FROM SYSIBM.SYSDATABASE
FETCH FIRST 10 ROWS ONLY
You must remember to put () after GENERATE_UNIQUE otherwise DB2 interprets GENERATE_UNIQUE
as the name of a column. If the above statement fails with anything else than a -904 then
GENERATE_UNIQUE is not available at the DB2 subsystem where you were executing the SQL
statement. If you are running DB2 version 7 you must ask your DB2 systems programmer to install
APAR PQ70901. When he or she has done that it should work. If you receive a -904 then the
GENERATE_UNIQUE function may not be properly installed or your z/OS hardware/software may not
be sufficiently upgraded to make GENERATE_UNIQUE work.
When the above SQL statement works and outputs ten timestamps then please note that they are
all different and in ascending order. The combination of GENERATE_UNIQUE and the TIMESTAMP
function delivers a unique timestamp for each returned row within the same SQL statement. If you make an
INSERT INTO ... SELECT * FROM ... then TIMESTAMP(GENERATE_UNIQUE()) will work in exactly
the same way and therefore the SELECT part may be programmed to return a unique timestamp
for each row.
Two INSERT statements executed concurrently against the same DB2 (or DB2 data sharing group)
may still result in a -803. This problem may also be solved by using GENERATE_UNIQUE by
defining a new unique key column (named for instance key_column) as a CHAR(13) FOR BIT DATA.
Columns with this definition can be assigned the value returned by GENERATE_UNIQUE and will
always be unique and ascending even in a data sharing group. This approach is of course most
easy to implement on new tables, while it will require a lot of adjustments if used on existing
tables. The good trick about using a key column defined as above is that you can perform
a TIMESTAMP(key_column) and get the exact date and time for the creation of the unique value.
In other words you get the same information as when using a TIMESTAMP key column and on top
of that you get full uniqueness.
At last I have to mention that DB2 version 9 and DB2 version 8 in socalled New Function Mode
(NFM) returns unreadable values for TIMESTAMP(GENERATE_UNIQUE()) if one of the tables in the
FROM part is a UNICODE table (SYSDATABASE is such a table). The result returned is a timestamp
in unicode value. This problem is solved by using a CHAR(TIMESTAMP(GENERATE_UNIQUE())).
Another detail is that in the result of a SELECT statement the GENERATE_UNIQUE values are
generated before any DB2 internal SORT. For instance you can try the following two SQL
statements in order to see the consequences of this:
SELECT CHAR(TIMESTAMP(GENERATE_UNIQUE()))
FROM SYSIBM.SYSDATABASE
ORDER BY DBID
FETCH FIRST 10 ROWS ONLY
;
SELECT CHAR(TIMESTAMP(GENERATE_UNIQUE()))
FROM SYSIBM.SYSDATABASE
ORDER BY NAME
FETCH FIRST 10 ROWS ONLY
;
In the first SQL statement the ten returned timestamps will not be in ascending order
as this SQL statement will trigger an internal DB2 sort (unless for some reason an index
is defined on DBID at your installation). In the last SQL statement the ten timestamps are
returned in ascending order because DB2 retrieves the rows in the order specified by an index
thus avoiding an internal sort.
Previous tip in english
Sidste danske tip
Tip list
|