7

在 Oracle PL/SQL 块中,为什么允许动态 sql

begin
    execute immediate 'drop table table_name';
end;

但静态不是吗?

begin
    drop table table_name;
end;

我希望答案比“因为这就是语言的工作原理”更有洞察力。

4

3 回答 3

9

答案是 PL/SQL 不支持动态多态性。它只支持静态多态,因为

所有 PL/SQL 都会为 Ada 生成一个“DIANA”-> Descriptive Intermediate Attributed Notation,这是一种树形结构的中间语言。编译器在内部使用 DIANA。

在编译时,PL/SQL 源代码被翻译成系统代码并生成相应的 DIANA。现在想想如果有一个像 create table 语句这样的 DDL 语句在编译时不存在,它将在运行程序后创建。那么您的 PL/SQL 引擎将如何生成 DIANA 呢????

DIANA 在 PL/SQL 中起着重要的作用,用于检查/验证子程序。这是必需的,因为我们知道子程序可以使用数据库对象,例如表、视图、同义词或其他存储过程。下次运行程序时,对象可能已更改/删除/丢弃。例如:有人可能删除了表,存储的过程或函数签名可能已更改。

这就是为什么通常使用 PL/SQL 来操纵数据库结构中的数据,而不是操纵那些结构的原因。

但是有一些方法可以使用动态 SQL 和 DBMS_SQL 包进行操作,但这些方法再次应谨慎使用。例如,如果你正在创建一个表,你应该首先检查这个表是否已经存在或者没有使用数据字典视图。

于 2013-03-05T20:58:33.797 回答
3

可能是因为否则一些代码会像:

  begin
    create table tmp (n number);
    insert into tmp values (1);
  end;

我们希望编译器知道在插入时该表存在。块的编译将使我更加困难。这是一个非常简单的案例,但我们可以很容易地想象一些条件分支,以及复杂的blabla。

但是,由于我们需要将 DDL 放在立即执行块中,因此限制可能更容易理解。

只是一个想法...

于 2013-03-05T19:41:54.960 回答
0

在执行/编译之前,oracle 检查在 pl/sql 块中引用的所有模式对象(如表、视图、存储过程等)的所有访问权限、有效性和依赖关系。但是 DDL 语句的问题在于它可以创建、更改或删除模式对象,因此它可以更改对象依赖关系。因此,我们可能指的是一个已使用 DDL 删除的对象。为了防止这种情况,我猜 plsql 块不允许直接 DDL 语句。但是我们仍然可以使用动态查询在 PL/SQL 块中包含 DDL。由于在这种情况下实际查询直到运行时才知道,基本上我们可以以动态 SQL 的形式隐藏 DDL 语句,并将 DDL 包含在 PL/SQL 块中。

您可以参考我的博客以通过示例来理解这个概念: Why oracle does not allow direct DDL statements inside the procedure (PLSQL BLOCK)

于 2020-05-19T18:04:53.087 回答