PLSQL绑定变量和宿主变量有啥区别

Posted

技术标签:

【中文标题】PLSQL绑定变量和宿主变量有啥区别【英文标题】:What is the difference between PLSQL Bind variables and Host variablesPLSQL绑定变量和宿主变量有什么区别 【发布时间】:2014-10-08 12:11:32 【问题描述】:

对于 PLSQL,“宿主变量”和“绑定变量”有什么区别?

来自 askTom 的 link 说“plsql 中的区别很模糊——它非常接近 sql”。那么那个微小的、“模糊”的区别是什么?

声明 1:

SELECT 1 FROM dual WHERE dummy = :B1;

声明 2:

SELECT 1 FROM dual WHERE dummy = v_var;

在这两个语句中,Statement 1 代表绑定变量,Statement 2 代表 Host 变量,对吗?

【问题讨论】:

绑定/主机变量仅适用于embedded SQL/PLSQL...Bind 实际上是从您的接口(Java 或 Pro*C)向 Oracle 发送一些值。而Host 是变量在您的界面中定义并从 Oracle 获取其价值...所以您的陈述变得荒谬。 PL/SQL 块中使用变量本身的任何 static SQL,都将以类似于绑定变量的方式隐式使用..(实际上是解析的 SQL/Plan..).. 因此,使用 PL/ SQL(直接在 Oracle 中执行,而不是通过 JDBC 或任何基于 OCI 的)字面上没有 NO 绑定变量。除非你有动态 SQL。 【参考方案1】:

考虑一下 C# 的这个 sn-p:

int    v_empno = 7369;
string v_ename;

OracleCommand cmd = con.CreateCommand();
cmd.Parameters.Add("paramEmpno", OracleDbType.Decimal, v_empno, ParameterDirection.Input);
cmd.CommandText = "select e.ename from scott.emp e where e.empno = :1";
v_ename = cmd.ExecuteScalar().ToString();

v_empnov_ename 是主机变量。在这里,您显式创建您的绑定变量,以在您的语句中用作 :1

考虑一下这个 PL/SQL 的 sn-p:

declare
   v_empno  number := 7369;
   v_ename  varchar2(10);
begin
   select e.ename
     into v_ename
     from scott.emp e
    where e.empno = v_empno;
   dbms_output.put_line(v_ename);
end;
/

再次声明的变量v_empnov_ename 可以被认为是宿主变量,但是当它们在PL/SQL 代码中的静态SQL 中使用时,它们会被PL/SQL 编译器/引擎自动转换为绑定变量- 您不必像 C# 示例中那样手动创建绑定变量。如果你检查这段 PL/SQL 实际执行的 SQL,它看起来像这样:

   select e.ename
     from scott.emp e
    where e.empno = :B1

PL/SQL 编译器会自动为您的v_empno PL/SQL 变量创建:B1 绑定变量。这就是 Tom Kyte 的意思,您无法真正正确区分 PL/SQL 中的主机变量和绑定变量。当您编写 PL/SQL 时,变量在 PL/SQL 代码中使用时是主变量,同时在嵌入式 SQL 代码中使用时它们是绑定变量。你不需要在 PL/SQL 中进行区分,编译器会为你处理。

【讨论】:

【参考方案2】:

根据documentation

主机变量是主机程序与 Oracle 之间通信的关键。通常,预编译程序将数据从主变量输入到 Oracle,Oracle 将数据输出到程序中的主变量。 Oracle 将输入数据存储在数据库列中,并将输出数据存储在程序主变量中。

主变量可以是任何解析为标量类型的任意 C 表达式。但是,主变量也必须是左值。还支持大多数主机变量的主机数组。

Bind variables 不是简单的文本值。它们的值被发送到数据库,数据库也可以设置它们的值。 PL/SQL 本身负责处理与绑定变量有关的大部分问题。每个对 PL/SQL 变量的引用实际上都是一个绑定变量。

例如:

int     empno; 
char    ename[10]; 
float   sal; 
... 
EXEC SQL SELECT ename, sal INTO :ename, :sal FROM emp 
     WHERE empno = :empno; 

empno, ename, sal are all Host variables
:empno, :ename, :sal are all bind variables

你可以看到类似的问题here

【讨论】:

本文档是指 Pro*C/C++ 预编译器。我认为术语“HOST VARIABLE”根本不适用于 PL/SQL。 非常感谢您的回答,但是,正如@Rusty 指出的那样,它指的是 Pro*C/C++ 预编译器而不是 PLSQL【参考方案3】:

绑定/宿主变量仅适用于embedded SQL/PLSQL...

Bind 实际上是从您的接口(Java 或 Pro*C)向 Oracle 发送一些值..

Host 是你的接口中定义的变量,并从 Oracle 获取它的值...

所以你的说法很荒谬。

PL/SQL 块中使用变量本身的任何 静态 SQL,都将以类似于绑定变量的方式隐式使用..

--表示该SQL的下一次执行可以重用该计划并且 游标将被共享.. 在自适应游标共享的情况下..

.. 因此,使用 PL/SQL(直接在 Oracle 中执行,而不是通过 JDBC 或任何基于 OCI)存在 NO 字面上的绑定变量.. 除非您有动态 SQL。

示例:

 EXECUTE IMMEDIATE 'SELECT NAME FROM EMP WHERE ID = : ID' USING V_MYID

这里:ID是绑定变量----(接受来自调用者的查询的值) 而V_MYID 是主机变量.....(在调用者/主机本身中定义)

这个概念类似于其他嵌入式 SQL 原则。

【讨论】:

以上是关于PLSQL绑定变量和宿主变量有啥区别的主要内容,如果未能解决你的问题,请参考以下文章

PLSQL使用绑定变量

如何利用AngularJS绑定两个控制器并变量赋值

sql select语句作为动态plsql块的绑定变量

Z-ORA-01745:无效的主机/绑定变量名 (PLSQL)

动态 PLSQL 中的错误绑定变量

如何在 PLSQL 过程中将绑定变量作为 IN OUT 参数传递