Are you new to DB2? Are you making a transition from either Oracle, Sybase or SQL Server? Are you trying to learn DB2 to make your resume look better? One of the immediate challenge for you to is to learn new stored procedure (SQL PL) language quickly. But if you have already used PL/SQL or T-SQL for your stored procedures, you are already half-way through to start programming in DB2 SQL PL language.
Learn from the experts who have coded in this language. In my opinion, this is the best way and this is how I learnt different programming languages in my career.
I will point you to an article written by Serge Rielau on how to backup and restore a schema in DB2. This article explains backup and restore of a schema in a way different than a traditional DBA will do using core DB2 tools. This is very useful when you want to accomplish backup / restore of the schema programmatically using SQL PL stored procedures. Please see the article for how to do the backup / restore of the schema using the code but I am going to use this code to explain few features of SQL PL.
First of all you will put together your scripts in a file and you have to define your SQL statement terminator.
$ db2 -td@ -f script.sql
--#SET TERMINATOR @
$ db2 -f script.sql
SET SCHEMA = ADMIN
@
SET PATH = SYSTEM PATH, ADMIN
@
CREATE TABLE COLUMNS LIKE SYSSTAT.COLUMNS
@
CREATE FUNCTION LOC_MATCH(src VARCHAR(150), dst VARCHAR(50))
RETURNS INTEGER
DETERMINISTIC NO EXTERNAL ACTION CONTAINS SQL
RETURN CASE
WHEN src IS NULL THEN NULL
WHEN LOCATE(dst, src) > 0 THEN 2
ELSE 1
END
@
CREATE FUNCTION LOC_MATCH(src VARCHAR(150), dst VARCHAR(50))
RETURNS INTEGER
DETERMINISTIC NO EXTERNAL ACTION CONTAINS SQL
BEGIN ATOMIC
IF src IS NULL THEN
RETURN NULL;
ELSEIF LOCATE(dst, src) > 0 THEN
RETURN 2;
ELSE
RETURN 1;
END IF;
END
@
DROP SPECIFIC FUNCTION DECODE3
@
CREATE FUNCTION DECODE(flag VARCHAR(1),
yestext VARCHAR(30),
notext VARCHAR(30))
RETURNS VARCHAR(30)
SPECIFIC DECODE3
CONTAINS SQL DETERMINISTIC NO EXTERNAL ACTION
RETURN CASE flag WHEN 'Y' THEN yestext
WHEN 'N' THEN notext
ELSE '' END
@
DROP SPECIFIC FUNCTION DECODE4
@
CREATE FUNCTION DECODE(flag VARCHAR(1),
yestext VARCHAR(30),
notext VARCHAR(30),
elsetext VARCHAR(30))
RETURNS VARCHAR(30)
SPECIFIC DECODE4
CONTAINS SQL DETERMINISTIC NO EXTERNAL ACTION
RETURN CASE flag WHEN 'Y' THEN yestext
WHEN 'N' THEN notext
ELSE elsetext END
@
DROP SPECIFIC FUNCTION composetype6
@
CREATE FUNCTION composetype(typeschema VARCHAR(128),
typename VARCHAR(128),
length INTEGER,
scale INTEGER,
codepage INTEGER,
pschemaname VARCHAR(128))
RETURNS VARCHAR(350)
SPECIFIC composetype6
CONTAINS SQL DETERMINISTIC NO EXTERNAL ACTION
RETURN CASE WHEN typeschema NOT IN ('SYSIBM', pschemaname)
THEN '"' || typeschema || '".' ELSE '' END
|| CASE WHEN typeschema = 'SYSIBM'
THEN typename
ELSE '"' || typename || '"' END
|| CASE WHEN typeschema = 'SYSIBM'
AND typename IN ('CHARACTER', 'VARCHAR',
'BLOB', 'CLOB', 'DECIMAL')
THEN CASE WHEN length = -1
THEN '()'
ELSE CASE WHEN typename = 'DECIMAL'
THEN '(' || RTRIM(CHAR(length)) || ','
|| RTRIM(CHAR(scale)) || ')'
ELSE '(' || RTRIM(CHAR(length)) || ')'
END
END
ELSE '' END
|| CASE WHEN typename IN ('CHARACTER', 'VARCHAR')
AND codepage = 0
THEN ' FOR BIT DATA'
ELSE '' END
@
DROP SPECIFIC FUNCTION composetype3
@
CREATE FUNCTION composetype(typeschema VARCHAR(128),
typename VARCHAR(128),
pschemaname VARCHAR(128))
RETURNS VARCHAR(350)
SPECIFIC composetype3
CONTAINS SQL DETERMINISTIC NO EXTERNAL ACTION
RETURN composetype(typeschema, typename, -1, 0, -1, pschemaname)
@
CREATE FUNCTION IS_COL_EXISTS
(
schemaName VARCHAR(128),
tabName VARCHAR(128),
colName VARCHAR(128)
)
RETURNS INTEGER
SPECIFIC IS_COL_EXISTS
READS SQL DATA DETERMINISTIC NO EXTERNAL ACTION
BEGIN ATOMIC
IF EXISTS (SELECT 1 FROM SYSCAT.COLUMNS
WHERE TABSCHEMA = schemaName
AND TABNAME = IS_COL_EXISTS.tabName
AND COLNAME = IS_COL_EXISTS.colname) THEN
RETURN 1;
ELSE
RETURN 0;
END IF;
END
@
CREATE PROCEDURE DROP_ALL_FOREIGN_KEYS
(
IN schemaName VARCHAR(128)
)
SPECIFIC DROP_ALL_FOREIGN_KEYS
MODIFIES SQL DATA NO EXTERNAL ACTION DETERMINISTIC
BEGIN
-- Drop all foreign key constraints
FOR theseFKeys
AS
SELECT 'ALTER TABLE '||TRIM(schemaName)||'.'||
TRIM(tabName)||' DROP CONSTRAINT '||
constname AS FKConst
FROM SYSCAT.TABCONST
WHERE tabschema = schemaName
AND type = 'F'
DO
EXECUTE IMMEDIATE theseFKeys.FKConst;
END FOR;
END
@
- Learn how you can call db2load system procedure to load the data in a table through a stored procedure. Isn’t that wonderful?
- See the usage of the dynamic SQL statement for ALTER TABLE statement. You can turn-off the logging temporarily by using ACTIVATE NOT LOGGED until first commit is used.
- See the usage of the SELECT tabname FROM (VALUES (‘COLDIST’), (‘COLUMNS’), (‘INDEXES’), (‘TABLES’)) AS T(tabname) statement. The FOR loop is executed to load the data in the 4 tables by using SELECT .. FROM (VALUES ..) statement.
- See the usage of the dynamic SQL statement by using the parameter markers.
IF copymode = 0 THEN
FOR thisStatistik AS cur CURSOR WITH HOLD FOR
SELECT tabname FROM (VALUES
('COLDIST'), ('COLUMNS'), ('INDEXES'), ('TABLES'))
AS T(tabname)
DO
SET txt = 'ALTER TABLE "' || adminschema || '".'
|| tabname || ' ACTIVATE NOT LOGGED INITIALLY '
|| 'WITH EMPTY TABLE';
EXECUTE IMMEDIATE txt;
CALL db2load(1, '',
'LOAD FROM ' || loaddirectory || 'SYSSTAT_' ||
|| ' tabname || '.IXF'
|| ' OF IXF LOBS FROM ' || loaddirectory || ' MESSAGES '
|| messagedirectory || 'SYSSTAT_' || tabname || '.MSG'
|| ' INSERT INTO ' || adminschema || '.' || tabname,
load_sqlcode, load_sqlmessage,
load_read, load_skipped, load_loaded, load_rejected,
load_deleted, load_committed, load_part_read,
load_part_rejected, load_part_partitioned,
load_mpp_summary);
IF load_sqlcode <> 0 THEN
SET load_sqlmessage = LTRIM(CHAR(load_sqlcode))
|| '|SYSSTAT_' || tabname || '|'
|| COALESCE(load_sqlmessage, '');
SIGNAL SQLSTATE '78000' SET MESSAGE_TEXT = load_sqlmessage;
END IF;
END FOR;
END IF;
SET txt = 'UPDATE SYSSTAT.COLDIST SET (colvalue, valcount, distcount) '
|| '= (?, ?, ?) WHERE tabschema = ? '
|| 'AND tabname = ? AND colname = ?';
PREPARE stmt FROM txt;