<?xml version="1.0" encoding="utf-8" standalone="yes"?><rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom"><channel><title>SQL on MarkJacobsen.net</title><link>https://test.markjacobsen.net/tags/sql/</link><description>Recent content in SQL on MarkJacobsen.net</description><generator>Hugo -- gohugo.io</generator><language>en-us</language><lastBuildDate>Thu, 03 Jan 2019 17:02:00 +0000</lastBuildDate><atom:link href="https://test.markjacobsen.net/tags/sql/index.xml" rel="self" type="application/rss+xml"/><item><title>Update modification timestamp on DB2 table automatically</title><link>https://test.markjacobsen.net/2019/01/update-modification-timestamp-on-db2-table-automatically/</link><pubDate>Thu, 03 Jan 2019 17:02:00 +0000</pubDate><guid>https://test.markjacobsen.net/2019/01/update-modification-timestamp-on-db2-table-automatically/</guid><description>&lt;p&gt;Ever want to update your modification timestamp field any time an update is made to the row without having to add application logic? Well, DB2 makes it relatively painless…&lt;/p&gt;
&lt;pre class="wp-block-code"&gt;&lt;code&gt;alter table XX.MY_TABLE add column last_updated_ts timestamp not null
generated by default for each row on update as row change timestamp&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Check out these resources for additional information…&lt;/p&gt;
&lt;ul class="wp-block-list"&gt;
 &lt;li&gt;
 https://www.ibm.com/support/knowledgecenter/SSEPGG_11.1.0/com.ibm.db2.luw.admin.dbobj.doc/doc/c0051498.html
 &lt;/li&gt;
 &lt;li&gt;
 https://www.ibm.com/support/knowledgecenter/SSEPGG_11.1.0/com.ibm.db2.luw.sql.ref.doc/doc/r0000888.html
 &lt;/li&gt;
&lt;/ul&gt;</description></item><item><title>DB2 Ownership Transfer</title><link>https://test.markjacobsen.net/2016/10/db2-ownership-transfer/</link><pubDate>Mon, 03 Oct 2016 20:46:00 +0000</pubDate><guid>https://test.markjacobsen.net/2016/10/db2-ownership-transfer/</guid><description>&lt;p&gt;If you ever get an error in DB2 along the lines of…&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;SQLCODE=-727, SQLSTATE=56098, SQLERRMC=1;-551;42501;MARKJ|EXECUTE|XX.PROC_P
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;…but in your code are executing the proc as another user (say “USR1”) instead of MARKJ, it may be that MARKJ created the proc and until recently still had the necessary access for executing everything in XX.PROC_P. Subsequently permissions were “fixed” and now stuff starts blowing up all over because MARKJ no longer has access. How to fix? Well, like all things I’m sure there are a million ways to do it, but the easiest in this situation was to have MARKJ transfer the ownership on everything he owned. To determine that, the following SQL was run to generate the commands, then the commands were run…&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;SELECT 
CASE ROUTINETYPE WHEN 'F' THEN
 'TRANSFER OWNERSHIP OF FUNCTION '||
 RTRIM(ROUTINESCHEMA)||'.'|| ROUTINENAME ||
 ' TO USER DB2DBA PRESERVE PRIVILEGES; '
ELSE
 'TRANSFER OWNERSHIP OF PROCEDURE '||
 RTRIM(ROUTINESCHEMA)||'.'|| ROUTINENAME ||
 ' TO USER DB2DBA PRESERVE PRIVILEGES; '
END
FROM SYSCAT.ROUTINES 
WHERE OWNER = 'MARKJ' 
WITH UR;
&lt;/code&gt;&lt;/pre&gt;</description></item><item><title>DB2 Stats vs Actual</title><link>https://test.markjacobsen.net/2015/07/db2-stats-vs-actual/</link><pubDate>Tue, 07 Jul 2015 14:30:00 +0000</pubDate><guid>https://test.markjacobsen.net/2015/07/db2-stats-vs-actual/</guid><description>&lt;p&gt;Ever have a DB2 query that all of a sudden went from performing just fine to being dog slow? If so, there may be an issue with the stats on one or more of the tables being used in the query. To check, run the SQL below replacing XX and TABLE_NM with your appropriate schema and table in 2 places…&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;-- What DB2 thinks the table count is
SELECT 'Stats' AS TYPE_X,
 CARD AS COUNT_NB,
 STATS_TIME AS UPDATED_TS
FROM SYSCAT.TABLES 
WHERE TABSCHEMA = 'XX' 
 AND TABNAME ='TABLE_NM'
 UNION
-- Actual table count
SELECT 'Actual' AS TYPE_X,
 COUNT(*) AS COUNT_NB,
 CURRENT_TIMESTAMP AS UPDATED_TS
FROM XX.TABLE_NM
FOR READ ONLY WITH UR
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;… if the record counts are way off, have your DBA do a runstats on the table in question followed by a rebind of any stored procs that use the table.&lt;/p&gt;</description></item><item><title>DB2 Recursive Query</title><link>https://test.markjacobsen.net/2015/04/db2-recursive-query/</link><pubDate>Fri, 03 Apr 2015 20:58:00 +0000</pubDate><guid>https://test.markjacobsen.net/2015/04/db2-recursive-query/</guid><description>&lt;p&gt;If you’ve ever had to do a recursive query in DB2 to get a hierarchy of records, feel free to use this as a starting point…&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;WITH LINKS (PARENT_ID, CHILD_ID, UPDATED_TS) AS 
 ( 
 SELECT ROOT.PARENT_ID, ROOT.CHILD_ID, ROOT.UPDATED_TS 
 FROM XX.EVENTS ROOT 
 WHERE ROOT.CHILD_ID = '234ASDFASDF' 
 UNION ALL 
 SELECT CHILD.PARENT_ID, CHILD.CHILD_ID, CHILD.UPDATED_TS 
 FROM LINKS PARENT, XX.EVENTS CHILD 
 WHERE PARENT.PARENT_ID = CHILD.CHILD_ID 
 ) 
SELECT PARENT_ID, CHILD_ID, UPDATED_TS 
FROM LINKS 
ORDER BY UPDATED_TS 
FOR READ ONLY WITH UR
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;… yes, newer versions of DB2 have this ability built in but you’re not always using the most recent version are you??&lt;/p&gt;
&lt;p&gt;Thanks to &lt;a href="http://mullinsconsulting.com/bp5.htm" target="_blank"&gt;this page&lt;/a&gt; for pointing me in the right direction.&lt;/p&gt;</description></item><item><title>How Much Space Is Being Used by 1 LOB / CLOB / BLOB in DB2</title><link>https://test.markjacobsen.net/2015/02/much-space-used-1-lob-clob-blob-db2/</link><pubDate>Wed, 04 Feb 2015 23:36:00 +0000</pubDate><guid>https://test.markjacobsen.net/2015/02/much-space-used-1-lob-clob-blob-db2/</guid><description>&lt;p&gt;Building off of yesterdays lesson on [how to determine how much space a table is using (including LOBs and Indexes)][1], there may come a time when you need to determine how much space 1 or more specific records are taking up. To do that, use the LENGTH() function which will return you how many bytes the field is using. Simply do some math to get a more useful value (like KB).&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;SELECT length(LOB_DATA_X) BYTE_A, length(LOB_DATA_X) / 1024 KB_A
FROM XX.MY_TABLE
FETCH FIRST 10 ROWS ONLY WITH UR FOR READ ONLY;[1]: http://markjacobsen.net/2015/02/get-space-used-lob-clob-blob-db2/
&lt;/code&gt;&lt;/pre&gt;</description></item><item><title>Get Space Used by LOB / CLOB / BLOB in DB2</title><link>https://test.markjacobsen.net/2015/02/get-space-used-lob-clob-blob-db2/</link><pubDate>Wed, 04 Feb 2015 03:07:00 +0000</pubDate><guid>https://test.markjacobsen.net/2015/02/get-space-used-lob-clob-blob-db2/</guid><description>&lt;p&gt;If you have a DB2 table and want to get information as to how much space a particular table is using, you could try and deduce it from things like the row length, or you could just query the view via a table function and make your life a heck of a lot easier.&lt;/p&gt;
&lt;p&gt;For instance, start with something like this…&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;SELECT * FROM TABLE(SYSPROC.ADMIN_GET_TAB_INFO('XX', 'MY_TABLE'));
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Previous versions of this function include ADMIN_GET_TAB_INFO_V97 and ADMIN_GET_TAB_INFO_V95. The nice thing is that it appears you don’t have to be a DBA to query the info which is nice for us app developers out there!&lt;/p&gt;
&lt;p&gt;Keep in mind that sizes returned are in KB, so you may want to convert the data to something more useful like so…&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;SELECT TRIM(TABSCHEMA) || '.' || TRIM(TABNAME) AS TABLE_NM,
 DATA_OBJECT_P_SIZE / 1024 AS DATA_P_SIZE_NB, 
 LOB_OBJECT_P_SIZE / 1024 AS LOB_P_SIZE_MB, 
 XML_OBJECT_P_SIZE / 1024 AS XML_P_SIZE_MB, 
 LONG_OBJECT_P_SIZE / 1024 AS LONG_P_SIZE_MB, 
 (DATA_OBJECT_P_SIZE + LOB_OBJECT_P_SIZE + XML_OBJECT_P_SIZE + LONG_OBJECT_P_SIZE) / 1024 AS TOTAL_P_SIZE_MB,
 INDEX_OBJECT_P_SIZE / 1024 AS INDEX_OBJECT_P_SIZE_MB
FROM TABLE(SYSPROC.ADMIN_GET_TAB_INFO('XX', 'MY_TABLE'));
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;See also: &lt;a href="http://www-01.ibm.com/support/knowledgecenter/SSEPGG_10.1.0/com.ibm.db2.luw.sql.rtn.doc/doc/r0052897.html?cp=SSEPGG_10.1.0%2F3-6-1-3-0-18&amp;#038;lang=en" target="_blank"&gt;this link&lt;/a&gt;&lt;/p&gt;</description></item><item><title>Generate test data to help debug DB2 SQL</title><link>https://test.markjacobsen.net/2014/09/generate-test-data-help-debug-db2-sql/</link><pubDate>Tue, 16 Sep 2014 15:24:00 +0000</pubDate><guid>https://test.markjacobsen.net/2014/09/generate-test-data-help-debug-db2-sql/</guid><description>&lt;p&gt;You can easily create test data to help debug SQL statements:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;with data (key, value) as
( values ('key1', 'a')
 , ('key2', null)
 , ('key3', 'z')
)
select 'min', min(coalesce(value,'')) from data
union
select 'max', max(coalesce(value,'')) from data
&lt;/code&gt;&lt;/pre&gt;</description></item><item><title>How to Tell What Objects Reference a DB2 Table</title><link>https://test.markjacobsen.net/2014/04/how-to-tell-what-objects-reference-a-db2-table/</link><pubDate>Tue, 15 Apr 2014 07:15:00 +0000</pubDate><guid>https://test.markjacobsen.net/2014/04/how-to-tell-what-objects-reference-a-db2-table/</guid><description>&lt;p&gt;This “little” 🙂 query will do it for you. Just change the where clause at the bottom…&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;SELECT Type_X AS &amp;quot;Type&amp;quot; 
, RefObj_X AS &amp;quot;Referencing Object&amp;quot; 
FROM ( 
SELECT RTRIM(SYSPROC.PROCSCHEMA)||'.'||RTRIM(SYSPROC.PROCNAME) AS RefObj_X 
, RTRIM(SYSPROC.PROCSCHEMA) AS Schema_X 
, RTRIM(SYSPROC.PROCNAME) AS Obj_X 
, RTRIM(PDEP.BSCHEMA)||'.'||RTRIM(PDEP.BNAME) AS BaseObj_X 
, 'Proc' AS Type_X 
FROM SYSCAT.PACKAGEDEP PDEP 
INNER JOIN SYSIBM.sysdependencies SYSDEP 
ON SYSDEP.BSCHEMA = PDEP.BSCHEMA 
AND SYSDEP.BNAME = PDEP.PKGNAME 
INNER JOIN SYSIBM.sysprocedures SYSPROC 
ON SYSDEP.DNAME = SYSPROC.SPECIFICNAME 

UNION ALL 

SELECT RTRIM(TRIGSCHEMA)||'.'||RTRIM(TRIGNAME) AS RefObj_X 
, RTRIM(TRIGSCHEMA) AS Schema_X 
, RTRIM(TRIGNAME) AS Obj_X 
, RTRIM(BSCHEMA)||'.'||RTRIM(BNAME) AS BaseObj_X 
, 'Trigger' AS Type_X 
FROM SYSCAT.TRIGDEP 

UNION ALL 

SELECT RTRIM(VIEWSCHEMA)||'.'||RTRIM(CAST((VIEWNAME) AS CHAR(126))) AS RefObj_X 
, RTRIM(VIEWSCHEMA) AS Schema_X 
, RTRIM(CAST((VIEWNAME) AS CHAR(126))) AS Obj_X 
, RTRIM(BSCHEMA)||'.'||RTRIM(BNAME) AS BaseObj_X 
, CASE DTYPE WHEN 'S' 
THEN 'SUMMARY TABLE' 
ELSE 'View' 
END AS Type_X 
FROM SYSCAT.VIEWDEP 

UNION ALL 

SELECT RTRIM(INDSCHEMA)||'.'||RTRIM(INDNAME) AS RefObj_X 
, RTRIM(INDSCHEMA) AS Schema_X 
, RTRIM(INDNAME) AS Obj_X 
, RTRIM(TABSCHEMA)||'.'||RTRIM(TABNAME) AS BaseObj_X 
, 'Index' AS Type_X 
FROM SYSCAT.INDEXES 

UNION ALL 

SELECT RTRIM(TABSCHEMA)||'.'||RTRIM(TABNAME) AS RefObj_X 
, RTRIM(TABSCHEMA) AS Schema_X 
, RTRIM(TABNAME) AS Obj_X 
, RTRIM(BASE_TABSCHEMA)||'.'||RTRIM(BASE_TABNAME) AS BaseObj_X 
, 'Alias' AS Type_X 
FROM SYSCAT.TABLES 
WHERE TYPE = 'A' 

UNION ALL 

SELECT DISTINCT RTRIM(CAST(RTRIM(TABSCHEMA) AS VARCHAR(126))) || '.' || RTRIM(TABNAME) AS RefObj_X 
, RTRIM(CAST(RTRIM(TABSCHEMA) AS VARCHAR(126))) AS Schema_X 
, RTRIM(TABNAME) AS Obj_X 
, RTRIM(REFTABSCHEMA)||'.'||RTRIM(REFTABNAME) AS BaseObj_X 
, 'Table' AS Type_X 
FROM SYSCAT.REFERENCES 
) AS RefTbl 
WHERE BaseObj_X = 'XX.MY_TABLE' 
ORDER BY 
Type_X 
, RefObj_X;&amp;lt;/pre&amp;gt;
&lt;/code&gt;&lt;/pre&gt;</description></item><item><title>When Was a DB2 Table Created and by Who?</title><link>https://test.markjacobsen.net/2014/03/when-was-a-db2-table-created-and-by-who/</link><pubDate>Thu, 27 Mar 2014 07:08:00 +0000</pubDate><guid>https://test.markjacobsen.net/2014/03/when-was-a-db2-table-created-and-by-who/</guid><description>&lt;p&gt;This little bit of SQL should help you determine who created a table or when it was created…&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;SELECT 
CASE TAB.TYPE 
WHEN 'A' THEN 'Alias' 
WHEN 'N' THEN 'Nickname' 
WHEN 'S' THEN 'MQT' 
WHEN 'T' THEN 'Table' 
WHEN 'V' THEN 'View' 
ELSE 'OTHER: '||TAB.TYPE 
END AS T_TYPE 
,RTRIM(TAB.TABSCHEMA)||'.'||TAB.TABNAME AS TABLE_NAME 
,DATE(CREATE_TIME) AS CREATED 
,DATE(ALTER_TIME) AS ALTERED 
,TAB.COLCOUNT AS COLUMNS 
,TAB.DEFINER AS CREATED_BY 
FROM SYSCAT.TABLES TAB 
WHERE TABSCHEMA = 'XX' 
ORDER BY TABLE_NAME 
FOR READ ONLY 
WITH UR;&amp;lt;/pre&amp;gt;
&lt;/code&gt;&lt;/pre&gt;</description></item><item><title>Find DB2 Fields Containing Carriage Returns, Line Feeds, or Both CRLF</title><link>https://test.markjacobsen.net/2014/03/find-db2-fields-containing-carriage-returns-line-feeds-or-both-crlf/</link><pubDate>Tue, 18 Mar 2014 07:59:55 +0000</pubDate><guid>https://test.markjacobsen.net/2014/03/find-db2-fields-containing-carriage-returns-line-feeds-or-both-crlf/</guid><description>&lt;pre&gt;&lt;code&gt;select * 
from HH.MY_TABLE 
where TEXT_X like '%' || chr(13) || chr(10) || '%' &amp;lt;/pre&amp;gt;
&amp;lt;p&amp;gt;&amp;lt;/p&amp;gt;


... or ... 


 select * 
 from HH.MY_TABLE 
 where TEXT_X like '%' || chr(10) || '%' &amp;lt;/pre&amp;gt;
 &amp;lt;p&amp;gt;&amp;lt;/p&amp;gt;
 
 
 ... or ... 
 
 
 select * 
 from HH.MY_TABLE 
 where TEXT_X like '%' || chr(13) || '%'&amp;lt;/pre&amp;gt;
&lt;/code&gt;&lt;/pre&gt;</description></item><item><title>Find time between records in a logging table with DB2</title><link>https://test.markjacobsen.net/2014/03/find-time-between-records-in-a-logging-table-with-db2/</link><pubDate>Mon, 17 Mar 2014 15:39:21 +0000</pubDate><guid>https://test.markjacobsen.net/2014/03/find-time-between-records-in-a-logging-table-with-db2/</guid><description>&lt;p&gt;One trick I’ve used for quite a while is to have stored procs “log” information to a table with the structure…&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;XX.SYS_PROC_AUD
(
PROC_X,
ACTIVITY_X,
CREATED_TS,
ERROR_NB
)
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;…which is great for seeing what’s going on across the board, on a proc by proc basis, or looking for specific things. But what about when management request “metrics” about how things are running? Well, since I already log stop and start of the procs to the aforementioned table, you can use a WITH query to help get run times of procs and even between procs without resorting to Excel like so…&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;WITH rows AS
 (
 SELECT ROW_NUMBER() OVER (ORDER BY CREATED_TS) AS rn, CREATED_TS, PROC_X
 FROM XX.SYS_PROC_AUD 
 WHERE (
 PROC_X = 'XX.FIRST_PROC_P' 
			 AND ACTIVITY_X = 'Starting Exec' 
 )
 OR
 (
 PROC_X = 'XX.LAST_PROC_P' 
			 AND ACTIVITY_X = 'Finished Exec' 
 )
 ORDER BY CREATED_TS DESC
 FETCH FIRST 1000 ROWS ONLY WITH UR
 )
SELECT mc.CREATED_TS as START_TS, 
 mp.CREATED_TS as END_TS, 
 TIMESTAMPDIFF(2, CHAR(mp.CREATED_TS - mc.CREATED_TS)) AS SEC, 
 TIMESTAMPDIFF(2, CHAR(mc.CREATED_TS - mpe.CREATED_TS)) AS SEC_BETWEEN_LAST
FROM rows mc
 INNER JOIN rows mp
 ON mc.rn = mp.rn - 1
 INNER JOIN rows mpe
 ON mc.rn = mpe.rn + 1
WHERE mc.PROC_X = 'XX.FIRST_PROC_P'
ORDER BY mc.CREATED_TS DESC
FETCH FIRST 100 ROWS ONLY WITH UR FOR READ ONLY
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Note: I prefer to see the most recent things first so you may need to adjust your ordering appropriately if you don’t like that setup.&lt;/p&gt;
&lt;p&gt;Thanks to &lt;a href="http://stackoverflow.com/questions/2357515/calculate-time-difference-between-two-rows-sql-server" target="_blank"&gt;this post&lt;/a&gt; for getting me started.&lt;/p&gt;</description></item><item><title>Find Nullable Columns in DB2 with no Null Values</title><link>https://test.markjacobsen.net/2014/03/find-nullable-columns-in-db2-with-no-null-values/</link><pubDate>Fri, 14 Mar 2014 07:52:43 +0000</pubDate><guid>https://test.markjacobsen.net/2014/03/find-nullable-columns-in-db2-with-no-null-values/</guid><description>&lt;p&gt;I’m not a fan of NULL columns. So check out the query below if you want to find DB2 fields that are defined as nullable, but which contain no null values. You can also modify the query to show you how many records contain null values. Make sure to set the COLS.TABSCHEMA in the WHERE predicate.&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;SELECT RTRIM(TAB.TABSCHEMA)||'.'||TAB.TABNAME AS TABLE_OBJECT_NAME 
, COLS.COLNAME AS COLNAME , COLS.TYPENAME AS 
TYPE ,RTRIM(CHAR(COLS.LENGTH))|| 
CASE COLS.SCALE 
WHEN 0 
THEN ' ' 
ELSE ','||RTRIM(CHAR(COLS.SCALE)) 
END || 
CASE COLS.TYPENAME 
WHEN 'VARCHAR' 
THEN ' AVG:'||RTRIM(CHAR(COLS.AVGCOLLEN)) 
ELSE ' ' 
END AS LENGTH 
,TAB.CARD as TAB_CARD 
,COLS.COLCARD AS COL_CARD 
,CASE 
WHEN NULLS ='Y' 
THEN 'NULL ('||RTRIM(CHAR(NUMNULLS))||')' 
WHEN NULLS = 'N' THEN 'NOT NULL' 
ELSE '??' END as NUM_NULLS 
,RTRIM(COLS.TABSCHEMA)||'.'||COLS.TABNAME||'2' AS SORTCOL,COLS.COLNO AS SORTCOL2 
FROM SYSCAT.COLUMNS COLS 
INNER JOIN SYSCAT.TABLES TAB ON (COLS.TABSCHEMA = TAB.TABSCHEMA AND COLS.TABNAME = TAB.TABNAME) 
WHERE RTRIM(COLS.TABSCHEMA) = 'XX' 
AND ( 
(NULLS = 'Y' AND NUMNULLS=0 AND TAB.CARD &amp;gt; 0) 
--OR (COLS.TYPENAME = 'VARCHAR' AND COLS.AVGCOLLEN &amp;gt;= COLS.LENGTH-2) 
) 
ORDER BY SORTCOL,SORTCOL2 
FOR READ ONLY WITH UR;
&lt;/code&gt;&lt;/pre&gt;</description></item><item><title>How to Truncate a DB2 Table</title><link>https://test.markjacobsen.net/2014/03/how-to-truncate-a-db2-table/</link><pubDate>Thu, 13 Mar 2014 07:43:57 +0000</pubDate><guid>https://test.markjacobsen.net/2014/03/how-to-truncate-a-db2-table/</guid><description>&lt;p&gt;There’s 2 ways to do this…&lt;/p&gt;
&lt;p&gt;The first way should work on any version of DB2. Make sure to add to add the savecount and nonrecoverable as seen below so you don’t put your table space into a bad condition.&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;{CALL SYSPROC.ADMIN_CMD('LOAD FROM /dev/null of del savecount 1000 replace into XX.MY_TABLE nonrecoverable')};
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;The seconds is easier but has only been around since v9.5 or v9.7…&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;TRUNCATE TABLE XX.MY_TABLE IMMEDIATE
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Just make sure you include that IMMEDIATE in there 🙂&lt;/p&gt;</description></item><item><title>DB2: When were index stats last updated on a table?</title><link>https://test.markjacobsen.net/2014/03/db2-when-were-index-stats-last-updated-on-a-table/</link><pubDate>Fri, 07 Mar 2014 20:51:56 +0000</pubDate><guid>https://test.markjacobsen.net/2014/03/db2-when-were-index-stats-last-updated-on-a-table/</guid><description>&lt;p&gt;To find out when stats were updated for an index, run the following SQL substituting your schema and table names…&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;SELECT IND.TABSCHEMA,
 IND.TABNAME,
 IND.INDNAME,
 IND.COLNAMES,
 IND.STATS_TIME AS IDX_STATS_TIME, 
 T.STATS_TIME TBL_STATS_TIME, 
 CASE T.VOLATILE
 WHEN 'C' THEN 'YES'
 ELSE T.VOLATILE
 END AS TBL_VOLATILE,
 T.OWNERTYPE AS TBL_OWNERTYPE,
 T.TYPE AS TBL_TYPE
FROM SYSCAT.INDEXES IND 
 LEFT OUTER JOIN SYSCAT.TABLES T
 ON IND.TABSCHEMA = T.TABSCHEMA
 AND IND.TABNAME = T.TABNAME
WHERE T.OWNERTYPE != 'S'
 AND IND.TABNAME = 'MY_TABLE' 
 AND IND.TABSCHEMA = 'XX' 
ORDER BY 
 IND.TABSCHEMA,
 IND.TABNAME,
 IND.INDNAME 
FOR READ ONLY WITH UR;
&lt;/code&gt;&lt;/pre&gt;</description></item><item><title>DB2 Stored Proc Performance Analysis</title><link>https://test.markjacobsen.net/2014/02/db2-stored-proc-performance-analysis/</link><pubDate>Tue, 04 Feb 2014 11:00:02 +0000</pubDate><guid>https://test.markjacobsen.net/2014/02/db2-stored-proc-performance-analysis/</guid><description>&lt;p&gt;Have you ever wondered what tables and indexes a DB2 stored proc are using? How about if the proc has been rebound since the stats were last updated? Are there even stats for the table you’re querying? Luckily I work with a very talented application DBA (&lt;a href="https://test.markjacobsen.net/people/fred-johnson/" target="_blank"&gt;Fred Johnson&lt;/a&gt;) who put together the following query to tell you all these sorts of things. It’s quite long, but all you need to do is set your proc in the “FILTER_PARMS” “VALUES” section at the top of the query.&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;-------------------------------------------------------------------------
-- DB2 for AIX QUERY
--PROCS WITH DEPENDENT TABLES INDEXES CALLED_PROCS AND OTHER OBJECTS 
--FLAG column shows possible stats issues. See FOOTNOTES
-------------------------------------------------------------------------
-- Directions: Change FILTER_PARMS,Cut and paste, run, examine output
-- More than 1 proc can be reviewed by adding addition lines
-------------------------------------------------------------------------
WITH FILTER_PARMS (ROUTINESCHEMA,ROUTINENAME) AS 
 (VALUES 
 ('XX','PROC1_P') 
 ,('XX','PROC2_P')
 ) 
,ROUTINEDEP (STOREDPROC,TEXTX,OBJECTNAME,CARD,BIND_STATS_CREATE_TIME,FLAG,SORTCOL) AS
(SELECT RTRIM(X.ROUTINESCHEMA)||'.'||X.ROUTINENAME AS STOREDPROC , 
 'PACKAGE' AS TEXTX ,RTRIM(P1.PKGSCHEMA)||'.'||P1.PKGNAME AS 
 OBJECTNAME ,' ' AS CARD
 , 'BIND: '||CHAR(DATE(P1.LAST_BIND_TIME))||'*'||CHAR(TIME(P1.LAST_BIND_TIME)) 
 AS BIND_STATS_CREATE_TIME 
 ,CASE
 WHEN P1.LAST_BIND_TIME &amp;lt; CURRENT_TIMESTAMP - 9 DAYS
 THEN '*STALE REBIND ' ELSE ' ' 
 END
 ||
 CASE
 WHEN P1.VALID = 'N' THEN '*PACKAGE INVALID '
 WHEN P1.VALID = 'X' THEN '*PACKAGE INOPERATIVE '
 ELSE '' END 
 
 AS FLAG 
 ,RTRIM(X.ROUTINESCHEMA)||X.ROUTINENAME||'1' AS SORTCOL
 FROM SYSCAT.PACKAGES P1
 INNER JOIN SYSCAT.ROUTINEDEP R
 ON (P1.PKGNAME = R.BNAME
 AND P1.PKGSCHEMA = R.ROUTINESCHEMA)
 INNER JOIN SYSCAT.ROUTINES X
 ON (R.ROUTINENAME = X.SPECIFICNAME
 AND R.ROUTINESCHEMA = X.ROUTINESCHEMA)
 INNER JOIN FILTER_PARMS FP
 ON (FP.ROUTINESCHEMA = X.ROUTINESCHEMA 
 AND FP.ROUTINENAME = X.ROUTINENAME)
 UNION
 --TABLES
 SELECT ' ' AS STOREDPROC , CASE
 WHEN P.BTYPE = 'A' THEN 'ALIAS'
 WHEN P.BTYPE = 'B' THEN 'TRIGGER'
 WHEN P.BTYPE = 'D' THEN 'SERVER DEF'
 WHEN P.BTYPE = 'F' THEN 'PROC/FUNC'
 WHEN P.BTYPE = 'I' THEN 'INDEX'
 WHEN P.BTYPE = 'M' THEN 'FUNCTION MAP'
 WHEN TAB.TYPE = 'N' THEN 'NICKNAME'
 WHEN P.BTYPE = 'O' THEN 'PRIVILEGE DEP'
 WHEN P.BTYPE = 'P' THEN 'PAGE SIZE'
 WHEN P.BTYPE = 'R' THEN 'STRUCT TYPE '
 WHEN P.BTYPE = 'S' THEN 'MQTABLE'
 WHEN P.BTYPE = 'T' THEN 'TABLE'
 WHEN P.BTYPE = 'U' THEN 'TYPED TABLE'
 WHEN P.BTYPE = 'V' THEN 'VIEW'
 WHEN P.BTYPE = 'W' THEN 'TYPED VIEW'
 ELSE ' ?' END AS TEXTX ,RTRIM(P.BSCHEMA)||'.'||
 P.BNAME AS OBJECTNAME ,RTRIM(CHAR(TAB.CARD)) AS CARD 
 ,'STATS:'||COALESCE(CHAR(DATE(TAB.STATS_TIME))||'*'||CHAR(TIME(TAB.STATS_TIME)) ,'NO STATS')
 AS BIND_STATS_CREATE_TIME
 ,CASE
 WHEN TAB.CARD = -1
 THEN '*NO TABLESTATS'
 WHEN TAB.STATS_TIME &amp;gt; P1.LAST_BIND_TIME
 THEN '*PROC BIND &amp;lt; STATS'
 ELSE ' '
 END 
 ||
 CASE
 WHEN TAB.STATUS &amp;lt;&amp;gt; 'N'
 THEN '*STATUS '||RTRIM(TAB.STATUS)
 ELSE '' 
 END 
 AS FLAG
 
 ,RTRIM(X.ROUTINESCHEMA)||X.ROUTINENAME||'2'||RTRIM(
 P.BSCHEMA)||'.'||P.BNAME||'2' AS SORTCOL
 FROM SYSCAT.PACKAGES P1
 INNER JOIN SYSCAT.ROUTINEDEP R
 ON (P1.PKGNAME = R.BNAME
 AND P1.PKGSCHEMA = R.ROUTINESCHEMA)
 INNER JOIN SYSCAT.ROUTINES X
 ON (R.ROUTINENAME = X.SPECIFICNAME
 AND R.ROUTINESCHEMA = X.ROUTINESCHEMA)
 INNER JOIN FILTER_PARMS FP
 ON (FP.ROUTINESCHEMA = X.ROUTINESCHEMA 
 AND FP.ROUTINENAME = X.ROUTINENAME)
 INNER JOIN SYSCAT.PACKAGEDEP P
 ON (P1.UNIQUE_ID = P.UNIQUE_ID
 AND P.PKGNAME = R.BNAME
 AND P.PKGSCHEMA = R.ROUTINESCHEMA)
 
 INNER JOIN SYSCAT.TABLES TAB
 ON (P.BSCHEMA = TAB.TABSCHEMA
 AND P.BNAME = TAB.TABNAME
 AND P.BTYPE IN ( 'T','N','S','U','W'))
 UNION
 --INDEXES
 SELECT ' ' AS STOREDPROC , ' INDEX' AS TEXTX ,RTRIM(P.BSCHEMA)
 ||'.'||P.BNAME AS OBJECTNAME ,RTRIM(CHAR(IND.FULLKEYCARD)) AS CARD
 ,'STATS:'||COALESCE(CHAR(DATE(IND.STATS_TIME))||'*'||CHAR(TIME(IND.STATS_TIME)),'NO STATS')
 AS BIND_STATS_CREATE_TIME 
 ,CASE
 WHEN IND.FULLKEYCARD = -1
 THEN '*NO INDEXSTATS'
 WHEN IND.STATS_TIME &amp;gt; P1.LAST_BIND_TIME THEN '*PROC BIND &amp;lt; STATS '
 ELSE ''
 END 
 ||CASE
 WHEN IND.STATS_TIME &amp;lt; TAB.STATS_TIME - 10 SECONDS
 THEN '** IND.STATS_TIME &amp;lt; TAB.STATS_TIME'
 ELSE '' END AS FLAG 
 ,RTRIM(X.ROUTINESCHEMA)||X.ROUTINENAME||'2'||RTRIM(IND.TABSCHEMA)||'.'||IND.TABNAME||'3'
 AS SORTCOL
 FROM SYSCAT.PACKAGES P1
 INNER JOIN SYSCAT.ROUTINEDEP R
 ON (P1.PKGNAME = R.BNAME
 AND P1.PKGSCHEMA = R.ROUTINESCHEMA)
 INNER JOIN SYSCAT.ROUTINES X
 ON (R.ROUTINENAME = X.SPECIFICNAME
 AND R.ROUTINESCHEMA = X.ROUTINESCHEMA)
 INNER JOIN FILTER_PARMS FP
 ON (FP.ROUTINESCHEMA = X.ROUTINESCHEMA 
 AND FP.ROUTINENAME = X.ROUTINENAME)
 INNER JOIN SYSCAT.PACKAGEDEP P
 ON (P1.UNIQUE_ID = P.UNIQUE_ID
 AND P.PKGNAME = R.BNAME
 AND P.PKGSCHEMA = R.ROUTINESCHEMA)
 INNER JOIN SYSCAT.INDEXES IND 
 ON (P.BSCHEMA = IND.INDSCHEMA
 AND P.BNAME = IND.INDNAME
 AND P.BTYPE = 'I')
 INNER JOIN SYSCAT.TABLES TAB
 ON (IND.TABSCHEMA = TAB.TABSCHEMA
 AND IND.TABNAME = TAB.TABNAME)
 UNION
 SELECT ' ' AS STOREDPROC , ' OTHER '||
 CASE
 WHEN XDEP.ROUTINETYPE = 'F' THEN 'FUNCTION '
 WHEN XDEP.ROUTINETYPE = 'M' THEN 'METHOD'
 WHEN XDEP.ROUTINETYPE = 'P' THEN 'STORED PROC'
 ELSE ' ?' END AS TEXTX
 ,RTRIM(XDEP.ROUTINESCHEMA)||'.'||XDEP.ROUTINENAME AS OBJECTNAME 
 ,' ' AS CARD 
 ,'CREATED:'||CHAR(DATE(XDEP.CREATE_TIME))
 AS BIND_STATS_CREATE_TIME
 ,CASE 
 WHEN XDEP.ROUTINETYPE = 'P' 
 THEN CASE
 WHEN NOT EXISTS
 (SELECT 1
 FROM FILTER_PARMS FP
 WHERE FP.ROUTINESCHEMA = XDEP.ROUTINESCHEMA
 AND FP.ROUTINENAME = XDEP.ROUTINENAME)
 THEN ','||'('||''''||RTRIM(XDEP.ROUTINESCHEMA)
 ||''''||','||''''||RTRIM(XDEP.ROUTINENAME)
 ||''''||')' 
 ELSE ' ' END
 ELSE ' ' END AS FLAG --('CH','GET_NEXTID_P') 
 ,RTRIM(X.ROUTINESCHEMA)||X.ROUTINENAME||'3' AS SORTCOL
 FROM SYSCAT.PACKAGES P1
 INNER JOIN SYSCAT.ROUTINEDEP R
 ON (P1.PKGNAME = R.BNAME
 AND P1.PKGSCHEMA = R.ROUTINESCHEMA)
 INNER JOIN SYSCAT.ROUTINES X
 ON (R.ROUTINENAME = X.SPECIFICNAME
 AND R.ROUTINESCHEMA = X.ROUTINESCHEMA)
 INNER JOIN FILTER_PARMS FP
 ON (FP.ROUTINESCHEMA = X.ROUTINESCHEMA 
 AND FP.ROUTINENAME = X.ROUTINENAME)
 INNER JOIN SYSCAT.PACKAGEDEP P
 ON (P1.UNIQUE_ID = P.UNIQUE_ID
 AND P.PKGNAME = R.BNAME
 AND P.PKGSCHEMA = R.ROUTINESCHEMA)
 INNER JOIN SYSCAT.ROUTINES XDEP
 ON (P.BNAME = XDEP.SPECIFICNAME
 AND P.BSCHEMA = XDEP.ROUTINESCHEMA)
 UNION
 --OTHER
 SELECT ' ' AS STOREDPROC , ' OTHER '||
 CASE
 WHEN P.BTYPE = 'A' THEN 'ALIAS'
 WHEN P.BTYPE = 'B' THEN 'TRIGGER'
 WHEN P.BTYPE = 'D' THEN 'SERVER DEF'
 WHEN P.BTYPE = 'F' THEN 'PROC/FUNC'
 WHEN P.BTYPE = 'I' THEN 'INDEX'
 WHEN P.BTYPE = 'M' THEN 'FUNCTION MAP'
 WHEN P.BTYPE = 'N' THEN 'NICKNAME'
 WHEN P.BTYPE = 'O' THEN 'PRIVILEGE DEP'
 WHEN P.BTYPE = 'P' THEN 'PAGE SIZE'
 WHEN P.BTYPE = 'R' THEN 'STRUCT TYPE '
 WHEN P.BTYPE = 'S' THEN 'MQTABLE'
 WHEN P.BTYPE = 'T' THEN 'TABLE'
 WHEN P.BTYPE = 'U' THEN 'TYPED TABLE'
 WHEN P.BTYPE = 'V' THEN 'VIEW'
 WHEN P.BTYPE = 'W' THEN 'TYPED VIEW'
 WHEN P.BTYPE = 'Q' THEN 'Sequence object'
 WHEN P.BTYPE = 'G' THEN 'Global temporary table'
 ELSE ' ?'||RTRIM(P.BTYPE) END AS TEXTX 
 ,RTRIM(P.BSCHEMA)||'.'||P.BNAME AS OBJECTNAME 
 ,' ' AS CARD
 , '' AS BIND_STATS_CREATE_TIME ,' '
 AS FLAG ,RTRIM(X.ROUTINESCHEMA)||X.ROUTINENAME||'4' AS SORTCOL
 FROM SYSCAT.PACKAGES P1
 INNER JOIN SYSCAT.ROUTINEDEP R
 ON (P1.PKGNAME = R.BNAME
 AND P1.PKGSCHEMA = R.ROUTINESCHEMA)
 INNER JOIN SYSCAT.ROUTINES X
 ON (R.ROUTINENAME = X.SPECIFICNAME
 AND R.ROUTINESCHEMA = X.ROUTINESCHEMA)
 INNER JOIN FILTER_PARMS FP
 ON (FP.ROUTINESCHEMA = X.ROUTINESCHEMA 
 AND FP.ROUTINENAME = X.ROUTINENAME)
 INNER JOIN SYSCAT.PACKAGEDEP P
 ON (P1.UNIQUE_ID = P.UNIQUE_ID
 AND P.PKGNAME = R.BNAME
 AND P.PKGSCHEMA = R.ROUTINESCHEMA)
 WHERE P.BTYPE NOT IN ( 'I','F','T','S','N','U','W')
 ) 
SELECT STOREDPROC,TEXTX,OBJECTNAME,CARD,BIND_STATS_CREATE_TIME,FLAG
 FROM ROUTINEDEP
 ORDER BY SORTCOL
 WITH UR;
-----------------------------------------------------------------------
-- FLAG column show possible stats mismatch where a
-- procs bind time &amp;lt; stats time for Tables/Indexes
--
-- Also review CARD, which shows row counts for tables based on stats
-- is that what you expect?
--
-- Flag column also generates values clause that you can cut and paste
-- into the values clause to review called procs using this query
------------------------------------------------------------------------
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;And a few things &lt;a href="https://test.markjacobsen.net/people/fred-johnson/" target="_blank"&gt;Fred&lt;/a&gt; suggested to be mindful of&amp;hellip; &amp;ldquo;It should work with DB2luw and has been tested in AIX v9.5-10.2. There is one major caveat. The query assumes one proc has only one specific name i.e., it only works for non-overloaded procs. It also uses at least one deprecated column, ROUTINENAME in ROUTINEDEP. Changing the proc to use specific names wouldn’t be a big deal.&amp;rdquo;&lt;/p&gt;
&lt;p&gt;Have fun, and if you use this or have any suggested enhancements, please leave a comment below.&lt;/p&gt;</description></item><item><title>DB2 Get Current MAX value for all IDENTITY Columns</title><link>https://test.markjacobsen.net/2014/01/db2-get-current-max-value-for-all-identity-columns/</link><pubDate>Fri, 17 Jan 2014 15:05:58 +0000</pubDate><guid>https://test.markjacobsen.net/2014/01/db2-get-current-max-value-for-all-identity-columns/</guid><description>&lt;p&gt;If you’ve ever dealt with DB2 IDENTITY columns chances are you may have wanted to know what the currently assigned max value is for all of the IDENTITY columns in the DB. If so, you can use the following SQL to generate the SQL that will give you your answer. Hope it helps!&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;select 'select '''||trim(t.tabname)||''', '''||trim(c.colname)||''', max('||trim(c.colname)||') from '||trim(t.tabschema)||'.'||trim(t.tabname)||' for read only with ur;'
from syscat.sequences s join syscat.tables t on
(s.seqschema=t.tabschema and s.create_time=t.create_time)
join syscat.columns c on
(t.tabschema=c.tabschema and t.tabname=c.tabname)
where s.seqname like 'SQL%'
and c.identity='Y'
&lt;/code&gt;&lt;/pre&gt;</description></item><item><title>DB2: How to find records with non-printable characters (SQLSTATE 01517)</title><link>https://test.markjacobsen.net/2013/12/db2-how-to-find-records-with-non-printable-characters-sqlstate-01517/</link><pubDate>Wed, 11 Dec 2013 14:17:09 +0000</pubDate><guid>https://test.markjacobsen.net/2013/12/db2-how-to-find-records-with-non-printable-characters-sqlstate-01517/</guid><description>&lt;p&gt;If you run a select statement and get the following error…&lt;/p&gt;
&lt;pre&gt;"SQLSTATE 01517: A character that could not be converted was 
replaced with a substitute character."&lt;/pre&gt;
&lt;p&gt;… you can use the TRANSLATE function to strip away printable chars, and compare that to a zero length string like so…&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;SELECT * 
FROM XX.TBL 
WHERE TRANSLATE(UPPER(FIELD_X),'','ABCDEFGHIJKLMNOPQRSTUVWXYZ1234567890!@#$%^&amp;amp;*()-=+/\{}[];:.,&amp;lt;&amp;gt;? ') &amp;lt;&amp;gt; '' 
FOR READ ONLY WITH UR;
&lt;/code&gt;&lt;/pre&gt;</description></item><item><title>How to concatenate multiple columns in a DB2 select statement to return a single column</title><link>https://test.markjacobsen.net/2013/12/how-to-concatenate-multiple-columns-in-a-db2-select-statement-to-return-a-single-column/</link><pubDate>Tue, 03 Dec 2013 15:27:23 +0000</pubDate><guid>https://test.markjacobsen.net/2013/12/how-to-concatenate-multiple-columns-in-a-db2-select-statement-to-return-a-single-column/</guid><description>&lt;p&gt;Use “||” like so…&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;SELECT LastName||', '||FirstName 
FROM [schema].[table]
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;If one of the columns is numeric you’ll probably want to convert to CHAR and TRIM like so…&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;SELECT LastName||', '||FirstName||' - '||TRIM(CHAR(EmplId))
FROM [schema].[table]
&lt;/code&gt;&lt;/pre&gt;</description></item><item><title>Extract and insert tables (or portions of them) in DB2 – similar to BCP for Sybase and SQL Server</title><link>https://test.markjacobsen.net/2013/12/extract-and-insert-tables-or-portions-of-them-in-db2-similar-to-bcp-for-sybase-and-sql-server/</link><pubDate>Mon, 02 Dec 2013 16:47:37 +0000</pubDate><guid>https://test.markjacobsen.net/2013/12/extract-and-insert-tables-or-portions-of-them-in-db2-similar-to-bcp-for-sybase-and-sql-server/</guid><description>&lt;p&gt;You’ll need to be in the DB2 Command Line for this. Also, the version of your DB2 client should match the version of the DB or be higher than the DB version (i.e. no using a version 7 client to go after a version 8 DB).&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;To get data out of a db2 table:&lt;/strong&gt;&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;db2 &amp;quot;export to [file_name] of [file_type] select * from [table]&amp;quot;
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;[file_name] is a fully qualified name of the ouput file&lt;br&gt;
[file_type] is either del (delimited) or ixf (db2 native format).&lt;br&gt;
[table] is a fully qualified table, nickname, or view&lt;/p&gt;
&lt;p&gt;For example:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;db2 &amp;quot;export to /home/user/people.ixf of ixf select * from db2dba.people&amp;quot;&amp;lt;/pre&amp;gt;
&amp;lt;p&amp;gt;&amp;lt;/p&amp;gt;


**To import data into a db2 table:**


 db2 &amp;quot;import from [file_name] of [file_type] commitcount [value] insert into [table]&amp;quot;&amp;lt;/pre&amp;gt;
 &amp;lt;p&amp;gt;&amp;lt;/p&amp;gt;
 
 
 For example:
 
 
 db2 &amp;quot;import from /home/user/people.ixf of ixf commitcount 10000 insert into db2dba.people&amp;quot;&amp;lt;/pre&amp;gt;
 &amp;lt;p&amp;gt;&amp;lt;/p&amp;gt;
 
 
 commitcount is optional but should be used to avoid filling up the transaction log. I generally use 10k to 20k.
 
 
 Notice on the export command you use SQL syntax to get the data. You could use a where clause. You can also select and insert specific columns (**_Strongly recommended_**). 
 
 
 The import command allows you to insert into, replace into (replaces existing data), and create into (creates a new table). 
 
 
 You may wish to consult the DB2 Command Reference manual for more information
&lt;/code&gt;&lt;/pre&gt;</description></item><item><title>DB2 Duplicate Key Debugging</title><link>https://test.markjacobsen.net/2013/11/db2-duplicate-key-debugging/</link><pubDate>Tue, 26 Nov 2013 18:13:40 +0000</pubDate><guid>https://test.markjacobsen.net/2013/11/db2-duplicate-key-debugging/</guid><description>&lt;p&gt;If you’ve ever gotten a DB2 error like this…&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;SQL0803N One or more values in the INSERT statement, UPDATE statement, 
or foreign key update caused by a DELETE statement are not valid because 
the primary key, unique constraint or unique index identified by &amp;quot;1&amp;quot; 
constrains table &amp;quot;XX.TABLE_NAME&amp;quot; from having duplicate values for 
the index key. SQLSTATE=23505
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;You may be asking yourself, but exactly which unique index is causing the problem?&lt;/p&gt;
&lt;p&gt;Use the info from the error along with this query to find out:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;SELECT *
FROM SYSCAT.INDEXES
WHERE IID = 1
 AND TABSCHEMA = 'XX'
 AND TABNAME = 'TABLE_NAME';
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Of course you will want to replace the WHERE clause conditions with your values.&lt;/p&gt;</description></item><item><title>Generate a GUID or UUID in DB2</title><link>https://test.markjacobsen.net/2013/10/generate-a-guid-or-uuid-in-db2/</link><pubDate>Wed, 30 Oct 2013 20:54:15 +0000</pubDate><guid>https://test.markjacobsen.net/2013/10/generate-a-guid-or-uuid-in-db2/</guid><description>&lt;p&gt;Want to generate the equivalent of a GUID or UUID in DB2? The closest you’ll get is with GENERATE_UNIQUE(), but beware that you need to do some conversion on it as the value is “BIT DATA” and not character data. To put the value into a typical CHAR or VARCHAR field (like you would with a java UUID), use this…&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;select TRIM(CHAR(HEX(GENERATE_UNIQUE()))) from sysibm.sysdummy1;
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;I should probably also mention that there is the IDENTITY and SEQUENCE, but the GENERATE_UNIQUE() function is the closest you’ll get to a GUID or UUID.&lt;/p&gt;</description></item><item><title>DB2 Incremental Delete</title><link>https://test.markjacobsen.net/2013/07/db2-incremental-delete/</link><pubDate>Mon, 15 Jul 2013 16:40:00 +0000</pubDate><guid>https://test.markjacobsen.net/2013/07/db2-incremental-delete/</guid><description>&lt;p&gt;Ever have to delete a lot of records from a table in DB2 and can’t truncate, but you keep filling the transaction log? One way of solving the problem without having to manually update ranges of values in a where clause is to do an incremental delete in a stored proc. Here’s an example/template to get you started…&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;WHILE EXISTS ( SELECT ITEM_ID 
		FROM XX.TABLE
		WHERE SOMETHING_NB = 1
		FETCH FIRST 1 ROWS ONLY )
DO
	DELETE FROM 
		(SELECT ROW_NUMBER() OVER() AS ROW_NB
		FROM XX.TABLE
		WHERE SOMETHING_NB = 1
		FETCH FIRST 20000 ROWS ONLY)
	WHERE ROW_NB &amp;lt;= 20000;
	
	IF ((L_SQLCODE_NB &amp;lt;&amp;gt; 0) AND (L_SQLCODE_NB &amp;lt;&amp;gt; 100)) THEN
		SIGNAL SQLSTATE '20003' SET MESSAGE_TEXT = 'Error deleting records';
	END IF; 
	
	COMMIT;
END WHILE;
&lt;/code&gt;&lt;/pre&gt;</description></item><item><title>Find DB2 Nicknames</title><link>https://test.markjacobsen.net/2013/01/find-db2-nicknames/</link><pubDate>Thu, 24 Jan 2013 15:19:28 +0000</pubDate><guid>https://test.markjacobsen.net/2013/01/find-db2-nicknames/</guid><description>&lt;p&gt;Want to see the nickname setup for a DB2 database?  Here’s a handy query…&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;SELECT 
 NICK.TABSCHEMA,
 NICK.TABNAME,
 NICK.SERVERNAME,
 NICK.OWNER,
 NICK.REMOTE_SCHEMA,
 NICK.REMOTE_TABLE,
 SRV.SERVERTYPE
FROM SYSCAT.NICKNAMES NICK
 INNER JOIN SYSCAT.SERVERS SRV
 ON (NICK.SERVERNAME = SRV.SERVERNAME);
&lt;/code&gt;&lt;/pre&gt;</description></item></channel></rss>