如何控制基于 DB2s 结构的 SQL 语句的执行?

Posted

技术标签:

【中文标题】如何控制基于 DB2s 结构的 SQL 语句的执行?【英文标题】:How can I control execution of a SQL statement based on the DB2s structure? 【发布时间】:2020-01-28 21:43:02 【问题描述】:

我们想要运行一个简单的 SQL 语句(删除和创建索引),但前提是旧索引尚未被删除。在查找IF in DB2 的语法后,我想到了这个:

IF EXISTS (SELECT indname FROM SYSCAT.INDEXES WHERE INDNAME = 'TEST_CREATE_INDEX_OLD') 
THEN 
    DROP INDEX TEST_CREATE_INDEX_OLD;
    create index TEST_CREATE_INDEX_NEW on example_table
    (
        id,
        another_field
    );
END IF;

当使用 SQuirrel(已经设置为使用 db2 运行)或通过命令行运行时,此脚本会导致错误:

一个意外的标记“IF EXISTS (SELECT indname FROM SYSCAT.INDEX”是 在“BEGIN-OF-STATEMENT”之后找到。预期的令牌可能包括: "".. SQLCODE=-104, SQLSTATE=42601, DRIVER=4.23.42 SQL 代码: -104,SQL 状态:42601

那么 - 我做错了什么?我是否遗漏了什么,或者是否有其他方法可以实现我的目标(检查数据库中的 $thing,执行适当的查询),但到目前为止我还没有想到?

【问题讨论】:

您的 Db2 版本和平台是什么? DB2 v11.1.2020, Win7 【参考方案1】:

如果IF 语句仅在复合 SQL 块中有效(即在存储过程/例程/函数/匿名块中)。

正如您的问题所示,它不是独立有效的,这就是 Db2 抛出 -104 错误的原因。

您可以通过在link 的免费在线 Db2 知识中心中查找 SQL0104N 来查找 sqlcode -104 的解释。

为了能够在 Squirrel-SQL 工具中使用复合 SQL,您需要配置 squirrel 以使用替代语句终止符。谷歌那个。在下面的示例中,我显示了 @ 的语句终止符(用于分隔块)。

这里有两种不同的方法可以用 Db2-Linux/Unix/Windows 做你想做的事,每种方法都使用一个匿名块。其他方法也是可行的。

在此示例中,只有在当前架构中存在索引名称时才会运行 drop-index:

begin declare v_index_exists integer default 0; select 1 into v_index_exists from syscat.indexes where indname = 'TEST_CREATE_INDEX_OLD'; if v_index_exists = 1 then execute immediate('drop index TEST_CREATE_INDEX_OLD'); execute immediate('create index TEST_CREATE_INDEX_NEW on example_table ( id, another_field)'); end if; end@

在此示例中,drop-index 将始终运行,但如果索引不存在,该块将不会中止(即它将继续并且不会引发任何错误)。

begin declare v_no_such_index integer default 0; declare not_exists condition for sqlstate '42704'; declare continue handler for not_exists set v_no_such_index=1; execute immediate('drop index TEST_CREATE_INDEX_OLD'); execute immediate('create index TEST_CREATE_INDEX_NEW on example_table ( id, another_field)'); end@

【讨论】:

【参考方案2】:

如果要使用 db2 复合语句,则必须使用另一个语句分隔符。 在 Squirrel 中:会话 -> 会话属性 -> SQL -> 语句分隔符 = @. Db2 中的索引由 2 个SYSCAT.INDEXES 列完全限定:INDSCHEMAINDNAME。因此,建议在 SYSCAT.INDEXEX 上的 SELECT 语句中使用这两个字段,如示例所示。 您不能在复合语句中使用静态 DDL 语句。请改用 EXECUTE IMMEDIATE 语句。 下面是一个模拟 UPDATE INDEX 的示例,用于模式中的索引等于会话中设置的 CURRENT SCHEMA 特殊注册表。

BEGIN
IF EXISTS (SELECT indname FROM SYSCAT.INDEXES WHERE INDSCHEMA = CURRENT SCHEMA AND INDNAME = 'TEST_CREATE_INDEX_OLD') 
THEN 
    EXECUTE IMMEDIATE 'DROP INDEX TEST_CREATE_INDEX_OLD';
    EXECUTE IMMEDIATE'
    create index TEST_CREATE_INDEX_NEW on example_table
    (
        id,
        another_field
    )
    ';
END IF;
END
@

【讨论】:

以上是关于如何控制基于 DB2s 结构的 SQL 语句的执行?的主要内容,如果未能解决你的问题,请参考以下文章

SQL编程

SQL语句的执行过程

PL/SQL控制语句(循环控制语句)

流程控制。

mybatis如何在控制台打印执行的sql语句

java jdbc 执行sql语句批量操作问题