如何控制基于 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
列完全限定:INDSCHEMA
和INDNAME
。因此,建议在 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 语句的执行?的主要内容,如果未能解决你的问题,请参考以下文章