1

My goal is pretty straightforward - if table has rows, drop it. Despite the fact that currently there are several similar answers none of them worked for me.

  1. DB2 Drop table if exists equivalent

Suggested solution:

IF EXISTS (SELECT name FROM sysibm.systables WHERE name = 'mylib.mytable') THEN
DROP TABLE mylib.mytable;END IF;

Result:

SQL State: 42601 Vendor Code: -199 Message: [SQL0199] Keyword IF not expected.
Valid tokens: ( CL END GET SET CALL DROP FREE HOLD LOCK OPEN WITH ALTER BEGIN
  1. Drop DB2 table if exists

Suggested solution:

--#SET TERMINATOR @
begin
  declare statement varchar(128);
  declare continue handle for sqlstate '42710' BEGIN END;
  SET STATEMENT = 'DROP TABLE MYLIB.MYTABLE';
  EXECUTE IMMEDIATE STATEMENT;
end @

Result:

Message: [SQL0104] Token HANDLE was not invalid. Valid tokens: HANDLER or, if replace handle with handler:

Message: [SQL0199] Keyword STATEMENT not expected. Valid tokens: SQL PATH RESULT SCHEMA CURRENT CONNECTION DESCRIPTOR.
  1. From answer about views

Suggested solution:

DROP TABLE MY_TABLE ONLY IF EXISTS source.

Result:

Message: [SQL0104] Token ONLY was not invalid. Valid tokens: RESTRICT CASCADE

So, I wonder if an alternate solution exists. CL solution is also interesting.

Community
  • 1
  • 1
im_infamous
  • 972
  • 1
  • 17
  • 29
  • 1
    Your question says you want to delete the table only if it contains records, but your examples attempt to delete the table if it exists. Do you want to delete the table if it exists but has zero rows? What about DDS-defined physical files that might potentially contain multiple members (similar to partitions)? – WarrenT Apr 24 '17 at 16:16
  • @WarrenT nice catch. Indeed, my goal is delete file that has rows, but the solution that would delete file with empty file member(i.e. 0 rows) also interesting. – im_infamous Apr 24 '17 at 17:59
  • 1
    BTW, on #1, you needed to wrap it in a BEGIN END block. On #2, you misspelled HANDLER. On #3, the ONLY IF EXISTS syntax is not valid on DB2 for i. – WarrenT Apr 26 '17 at 19:54
  • @WarrenT I agree, there may be errors, but all these approaches is just my compilation of answers so I expect that they will solve the problem. Anyway, none of answers for #1 did not work for me even with BEGIN END block. – im_infamous Apr 27 '17 at 08:05
  • Using an ad hoc BEGIN END block is a feature that might not be available to you if you are on an older release without any TRs applied over the last few years. – WarrenT May 12 '17 at 07:10

4 Answers4

2

I'm assuming you may want to do this more than once, so a procedure might be in order.

CREATE or replace PROCEDURE   DROP_LIVE_TABLE
  (in  @table        varchar(10)   
  ,in  @library      varchar(10)
  )
BEGIN
  declare @stmt      varchar(100);
  declare @cnt       int;

  IF exists( select * from systables
               where sys_dname = @library
                 and sys_tname = @table
                 and table_type in ('P','T')
           ) THEN
    SELECT int(sum(number_rows))
      INTO @cnt
      from SYSTABLESTAT
        where sys_dname = @library
          and sys_tname = @table
      ;
    IF @cnt > 0 THEN
      set @stmt = 'DROP TABLE '||@library||'.'||@table||' CASCADE';
      execute immediate @stmt; 
    END IF;
  END IF;
  RETURN;
END;  

The CASCADE keyword causes any dependent objects such as indexes, logical files, views, or such to be deleted as well.

WarrenT
  • 4,502
  • 19
  • 27
  • So, I've tried to create procedure with the source you kindly shared `Procedure DRPLIVETBL was created in LIB`. Then call it `CALL PGM(DRPLIVETBL) PARM(LIB TESTFILE)` and it gives me `Application error. MCH3601 unmonitored by DRPLIVETBL at statement 000000000` which is giving me no clue what happened. File exists, I've double check that. – im_infamous Apr 27 '17 at 07:29
  • I wish I could accept your answer too - it looks promising, but the jmarkmurphy's solution really works as-is. No offence. Anyway, +1. – im_infamous Apr 27 '17 at 07:40
  • Are you trying to CALL it directly from CL? It's an SQL stored procedure, *not* a *PGM object. You use the SQL CALL statement, not the CL CALL command. Those are 2 very different things, and are not interchangeable. – WarrenT May 12 '17 at 07:04
1

Here is a CL answer to this question:

         PGM        PARM(&FILENAME)

         DCL        VAR(&FILENAME) TYPE(*CHAR) LEN(10)
         DCL        VAR(&NUMRECS) TYPE(*DEC) LEN(10 0)

         RTVMBRD    FILE(&FILENAME) NBRCURRCD(&NUMRECS)
         IF         COND(&NUMRECS > 0) THEN(DLTF +
                      FILE(&FILENAME))

OUT:     ENDPGM

This solution would have trouble if the physical file has dependencies such as indexes or logical files. Those dependencies would have to be deleted first.

The solution by @danny117 on the other hand does not work in all environments. For example I was unable to coerce it to work in SQuirreL client. But it does work in i Navigator. It also works in RUNSQLSTM, but I was unable to determine how to make it work with unqualified table references. If the tables are unqualified, RUNSQLSTM uses the default collection from DFTRDBCOL. The CURRENT_SCHEMA special register does not return the value from DFTRDBCOL.

Here is the if table has rows drop it solution using a compound statement:

begin
  if( exists(
    select 1 from qsys2.systables
    where table_schema = 'MYLIB'
      and table_name = 'MYTABLE'
  )) then
    if( exists(
      select 1 from mylib.mytable
    )) then
      drop table mylib.mytable;
    end if;
  end if;
end;

I am guessing at the reason you would want to do this, but if it is to allow creation of a new table, then best way may be with a CREATE OR REPLACE TABLE if you are at IBM i v7.2 or greater.

If all you want to do is make sure you have an empty table, TRUNCATE (v7.2+) or DELETE may be better options.

jmarkmurphy
  • 11,030
  • 31
  • 59
  • 1
    Actually, an SQL solution should be feasible on IBM i, and could easily handle the issue of dependent logicals, indexes, views, MQT's, etc. – WarrenT Apr 24 '17 at 16:06
  • Thank you for that, @Warrant. I was unaware that `BEGIN` could be used outside a stored procedure. apparently it does work in some environments, and I have amended my answer appropriately. – jmarkmurphy Apr 24 '17 at 19:32
  • I agree, the SQL source you've shared works (even from SQL console in Navigator for i). Anyone could check it on pub400.com. `CL` solution is interesting but has a high integration threshold - the user must have the authority and knowledge to compile, use and maintain resulting `CLP`, so SQL solution is more preferable. – im_infamous Apr 27 '17 at 07:51
1

Drop table if exists using atomic statement.

BEGIN ATOMIC                  
IF( EXISTS(                   
SELECT 1 FROM TABLES           
WHERE TABLE_SCHEMA = 'MYLIB'   
AND TABLE_NAME = 'MYTABLE' 
)) THEN                       
DROP TABLE MYLIB/MYTABLE;   
END IF;                       
END;                          
danny117
  • 5,581
  • 1
  • 26
  • 35
0

try this:

BEGIN    
   IF EXISTS (SELECT NAME FROM QSYS2.SYSTABLES WHERE TABLE_SCHEMA = 'YOURLIBINUPPER' AND TABLE_NAME = 'YOURTABLEINUPPER') THEN           
      DROP TABLE YOURLIB.YOURTABLE;                             
   END IF;                                                        
END  ;
Esperento57
  • 16,521
  • 3
  • 39
  • 45