![](https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhmCEs2ea2njVI0MXRCdHSM3Uu1AwiMtHyN6tb5noqLOEQRDVmq2GTpS_jnsjmez9jRpmjOMQlCbECvNtzZ0nBuUfsdNrTuYOY8I-TjxGr3vODwsOpuDESGJ3qsytW1aVWkKkqmQndH7Pl3o1WEPwL0yupniP9LhUzOpkwRIat2APT2UECwctc0VtxgZq4/s200/sql.png)
Last month I wrote about a way to list all of the unused virtual devices in your partition. In response to the article I received a question: "Is there a way to then delete these devices, other than manually going through? One system I just did has over 5,000 devices...."
The answer, of course, is yes there is. Before I give my final result let me go through the steps I did to create a SQL script to delete the unused virtual devices.
I can identify the virtual devices using the Object Statistics SQL Table function. I do not want to repeat myself. For the details read my previous article.
I decide to create a Common Table Expression, CTE, as it was just "neater". In the first part of the statement I would create a virtual table of all the eligible virtual devices, and in the second I would delete them. To start with I just want to make sure I gather the data I expected, therefore, my first statement did not do any deleting.
This was my first statement to gather the eligible virtual devices, and create the command string to delete them:
01 WITH T0(OBJNAME,CRTDATE,LASTUSEDDATE) 02 AS 03 (SELECT OBJNAME,DATE(OBJCREATED),DATE(LAST_USED_TIMESTAMP) 04 FROM TABLE(QSYS2.OBJECT_STATISTICS('QSYS','DEVD')) 05 WHERE OBJATTRIBUTE = 'DSPVRT' 06 AND LAST_USED_TIMESTAMP < CURRENT_TIMESTAMP - 6 MONTHS) 07 SELECT OBJNAME,CRTDATE,LASTUSEDDATE, 08 'DLTDEVD DEVD(' || OBJNAME || ')' AS "Command" 09 FROM T0 ; |
Line 1: All CTE start with "WITH". I always call my first virtual table T0. It will contain three columns:
- OBJNAME: Virtual device name
- CRTDATE: The date the object was created
- LASTUSEDDATE: The date the object was last used
Lines 3 – 6: This is the SQL statement to create the virtual table T0. Rather than use timestamp values for the Create date and Last Used date I converted the timestamp columns returned from Object Statistics to dates, using the Date scalar function. And I only want to return the virtual devices that have not been used in the last 6 months, line 6.
Lines 7 – 9: In the second part I can use the Select statement to list the contents of T0, and create a new column that contains the command I would use the delete eligible virtual devices, in a column I have called "Command".
The first four results are:
OBJNAME CRTDATE LASTUSEDDATE Command ----------- ----------- ------------ ------------------------ QPADEV0001 2021-05-14 2023-12-19 DLTDEVD DEVD(QPADEV0001) QPADEV0002 2021-05-15 2023-12-07 DLTDEVD DEVD(QPADEV0002) QPADEV0003 2021-05-15 2023-12-07 DLTDEVD DEVD(QPADEV0003) QPADEV0004 2021-05-15 2023-12-07 DLTDEVD DEVD(QPADEV0004) |
I am not going to want to watch my statement delete, say, 5,000 virtual devices so I would want to create a SQL statement I could put in a program. I am going to use the QCMDEXC scalar function to do the deleting. It returns a return code; therefore, I need to create an output file that the return code and other pertinent columns can be in. To accomplish this I need to take the previous SQL statement and wrap it in a "CREATE TABLE" expression that will generate table when the statement is executed.
My statement now looks like:
01 CREATE TABLE QTEMP.OUTFILE 02 (DEVICE_NAME,CREATE_DATE,LAST_USED_DATE, 03 DELETE_COMMAND,RETURN_CODE) 04 AS 05 (WITH T0(OBJNAME,CRTDATE,LASTUSEDDATE) 06 AS 07 (SELECT OBJNAME,DATE(OBJCREATED),DATE(LAST_USED_TIMESTAMP) 08 FROM TABLE(QSYS2.OBJECT_STATISTICS('QSYS','DEVD')) 09 WHERE OBJATTRIBUTE = 'DSPVRT' 10 AND LAST_USED_TIMESTAMP < CURRENT_TIMESTAMP - 6 MONTHS) 11 SELECT OBJNAME,CRTDATE,LASTUSEDDATE, 12 'DLTDEVD DEVD(' || OBJNAME || ')', 13 QSYS2.QCMDEXC('DLTDEVD DEVD(' || OBJNAME || ')') 14 FROM T0) 15 WITH DATA ; |
Line 1: I am calling this table OUTFILE and placing it in the library QTEMP.
Lines 2 and 3: I am going to give the columns in the table meaningful names, so I do not have to describe what information they contain.
Lines 5 – 12: The same as my previous statement.
Line 13: This is where I am using the QCMDEXC scalar function to perform delete of the virtual device. The scalar function returns "1" if it is successful, and "-1" is it fails.
When I execute the above I generate the table in QTEMP. To view the contents of the table I would use:
01 SELECT * FROM QTEMP.OUTFILE ; |
The first four results are:
DEVICE_NAME CREATE_DATE LAST_USED_DATE DELETE_COMMAND RETURN_CODE ----------- ----------- -------------- ------------------------ ----------- QPADEV0001 2021-05-14 2023-12-19 DLTDEVD DEVD(QPADEV0001) 1 QPADEV0002 2021-05-15 2023-12-07 DLTDEVD DEVD(QPADEV0002) 1 QPADEV0003 2021-05-15 2023-12-07 DLTDEVD DEVD(QPADEV0003) 1 QPADEV0004 2021-05-15 2023-12-07 DLTDEVD DEVD(QPADEV0004) 1 |
As the Return Code is all "1" then I know I deleted those virtual devices.
I can now take that statement and put it in a RPG program:
01 **free 02 exec sql DROP TABLE IF EXISTS QTEMP.OUTFILE ; 03 exec sql CREATE TABLE QTEMP.OUTFILE 04 (DEVICE_NAME,CREATE_DATE,LAST_USED_DATE, 05 DELETE_COMMAND,RETURN_CODE) 06 AS 07 (WITH T0(OBJNAME,CRTDATE,LASTUSEDDATE) 08 AS 09 (SELECT OBJNAME,DATE(OBJCREATED),DATE(LAST_USED_TIMESTAMP) 10 FROM TABLE(QSYS2.OBJECT_STATISTICS('QSYS','DEVD')) 11 WHERE OBJATTRIBUTE = 'DSPVRT' 12 AND LAST_USED_TIMESTAMP < CURRENT_TIMESTAMP - 6 MONTHS) 13 SELECT OBJNAME,CRTDATE,LASTUSEDDATE, 14 'DLTDEVD DEVD(' || OBJNAME || ')', 15 QSYS2.QCMDEXC('DLTDEVD DEVD(' || OBJNAME || ')') 16 FROM T0) 17 WITH DATA ; 18 *inlr = *on ; |
Line 2: Here I use the DROP TABLE statement to delete the Table, if it exists.
Lines 3 – 17: This statement is the same as the previous one.
I can then call the program and know that all of my old unused virtual devices will be deleted.
This article was written for IBM i 7.5, and should work for some earlier releases too.
Very useful tip, once again.
ReplyDeleteThank you Simon.