【问题标题】:Drop table if it exists with DB2/400 SQL如果表存在,则使用 DB2/400 SQL 删除表
【发布时间】:2017-04-24 08:47:11
【问题描述】:

我的目标非常简单 - 如果表有行,则删除它。 尽管目前有几个类似的答案,但没有一个对我有用。

  1. DB2 Drop table if exists equivalent

建议的解决方案:

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

结果:

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

建议的解决方案:

--#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 @

结果:

Message: [SQL0104] Token HANDLE was not invalid. Valid tokens: HANDLER 或者,如果将 handle 替换为 handler

Message: [SQL0199] Keyword STATEMENT not expected. Valid tokens: SQL PATH RESULT SCHEMA CURRENT CONNECTION DESCRIPTOR.
  1. 来自answer关于观看次数

建议的解决方案:

DROP TABLE MY_TABLE ONLY IF EXISTSsource.

结果:

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

所以,我想知道是否存在替代解决方案。 CL 解决方案也很有趣。

【问题讨论】:

  • 您的问题说您只想删除包含记录的表,但您的示例尝试删除该表(如果存在)。如果该表存在但有零行,您要删除它吗? DDS 定义的可能包含多个成员(类似于分区)的物理文件呢?
  • @WarrenT 不错。事实上,我的目标是删除包含行的文件,但删除文件成员为空(即 0 行)的文件的解决方案也很有趣。
  • 顺便说一句,在 #1 上,您需要将其包装在 BEGIN END 块中。在 #2 上,您拼错了 HANDLER。在 #3 上,ONLY IF EXISTS 语法在 DB2 for i 上无效。
  • @WarrenT 我同意,可能会有错误,但所有这些方法只是我对答案的汇编,所以我希望它们能解决问题。无论如何,即使使用 BEGIN END 块,#1 的任何答案都对我不起作用。
  • 使用临时 BEGIN END 块是一项功能,如果您使用的是过去几年未应用任何 TR 的旧版本,您可能无法使用该功能。

标签: sql db2 ibm-midrange db2-400


【解决方案1】:

我假设您可能想要多次执行此操作,因此可能需要一个程序。

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;  

CASCADE 关键字会导致索引、逻辑文件、视图等任何相关对象也被删除。

【讨论】:

  • 所以,我尝试使用您分享的源代码 Procedure DRPLIVETBL was created in LIB 创建程序。然后称它为CALL PGM(DRPLIVETBL) PARM(LIB TESTFILE),它给了我Application error. MCH3601 unmonitored by DRPLIVETBL at statement 000000000,这让我不知道发生了什么。文件存在,我已经仔细检查过。
  • 我希望我也能接受您的回答 - 看起来很有希望,但 jmarkmurphy 的解决方案确实可以按原样工作。没有恶意。无论如何,+1。
  • 你想直接从 CL 调用它吗?它是一个 SQL 存储过程,不是 *PGM 对象。您使用 SQL CALL 语句,而不是 CL CALL 命令。这是两个非常不同的东西,不能互换。
【解决方案2】:

这是这个问题的 CL 答案:

         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

如果物理文件具有索引或逻辑文件等依赖项,则此解决方案会出现问题。必须先删除这些依赖项。

另一方面,@danny117 的解决方案并不适用于所有环境。例如,我无法强制它在 SQuirreL 客户端中工作。但它确实适用于 i Navigator。它也适用于RUNSQLSTM,但我无法确定如何使其与不合格的表引用一起使用。如果表不合格,RUNSQLSTM 使用来自DFTRDBCOL 的默认集合。 CURRENT_SCHEMA 特殊寄存器不返回来自DFTRDBCOL 的值。

这里是 if table has rows drop it 使用复合语句的解决方案:

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;

我猜测您想要这样做的原因,但如果是为了允许创建新表,那么如果您使用的是 IBM i v7.2 或更高版本,那么最好的方法可能是使用CREATE OR REPLACE TABLE

如果您只想确保有一张空桌子,TRUNCATE (v7.2+) 或 DELETE 可能是更好的选择。

【讨论】:

  • 实际上,SQL 解决方案在 IBM i 上应该是可行的,并且可以轻松处理依赖逻辑、索引、视图、MQT 等问题。
  • 谢谢你,@Warrant。我不知道BEGIN 可以在存储过程之外使用。显然它在某些环境中确实有效,我已经适当地修改了我的答案。
  • 我同意,您共享的 SQL 源代码有效(甚至来自 Navigator for i 中的 SQL 控制台)。任何人都可以在 pub400.com 上查看。 CL 解决方案很有趣,但集成门槛很高——用户必须有编译、使用和维护生成的CLP 的权限和知识,因此 SQL 解决方案更可取。
【解决方案3】:

使用原子语句删除表(如果存在)。

BEGIN ATOMIC                  
IF( EXISTS(                   
SELECT 1 FROM TABLES           
WHERE TABLE_SCHEMA = 'MYLIB'   
AND TABLE_NAME = 'MYTABLE' 
)) THEN                       
DROP TABLE MYLIB/MYTABLE;   
END IF;                       
END;                          

【讨论】:

  • 我能够通过将TABLES 替换为QSYS2.SYSTABLES 在i Navigator 中完成这项工作。它在 SQuirreL 客户端中不起作用。
  • 表格可能是 v7r3 我能够从我的 iseries 上的表格中提示列
  • 是的 Tables 是 V7R3 中 qsys2.systables 的一个视图,我在上面做了 dspfd
【解决方案4】:

试试这个:

BEGIN    
   IF EXISTS (SELECT NAME FROM QSYS2.SYSTABLES WHERE TABLE_SCHEMA = 'YOURLIBINUPPER' AND TABLE_NAME = 'YOURTABLEINUPPER') THEN           
      DROP TABLE YOURLIB.YOURTABLE;                             
   END IF;                                                        
END  ;

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2012-01-06
    • 1970-01-01
    • 2020-09-26
    • 1970-01-01
    • 1970-01-01
    • 2016-02-15
    • 2019-04-03
    相关资源
    最近更新 更多