在 where 子句中使用 Oracle SQL 变量时遇到问题

Posted

技术标签:

【中文标题】在 where 子句中使用 Oracle SQL 变量时遇到问题【英文标题】:Trouble using Oracle SQL variable in where clause 【发布时间】:2013-01-18 15:11:07 【问题描述】:

我正在尝试编写一个脚本来帮助处理众多“此操作列表发生了什么”类型的调用,但我在做一些最简单的操作时遇到了困难。

我正在尝试声明一个变量并在查询的 where 子句中使用它。我已经删除了与查询无关的所有内容,试图让这个核心功能发挥作用。

id 通常是 18 位数字,但偶尔会包含字母数字,因此它是 varchar。我试图与之比较的列是一个 18 字节的 varchar 字段。

declare
  id_to_check VARCHAR(18);  

begin
  id_to_check := '549576015500000109';

select 
  txn_timestamp, exception_type
from cut.event
where irn_id = id_to_check;

end;

每次它抛出一个错误:'在这个选择语句中应该有一个 INTO 子句'。我了解 INTO 的工作原理,即如果我想将选择的结果分配给变量,但我不明白在这种情况下这将如何应用,因为我没有将查询结果分配给变量?

另一件令人沮丧的事情是我实际上正在关注 docs.oracle.com 上的文档。

http://docs.oracle.com/cd/B19306_01/appdev.102/b14261/overview.htm#LNPLS001.

我也查看了各种谷歌搜索结果,但如果不先选择变量,我无法弄清楚如何与变量进行比较,但正如你所见,我无法选择,因为我只出于比较的原因需要它吗?

亲切的问候, 伊恩

【问题讨论】:

【参考方案1】:

如果您在 PL/SQL 中做某事,Raphaël Althaus 的回答适用,但我不确定这是否真的是您想要的。听起来您想要一个普通的 SQL 查询,但您希望能够向它传递一个值?假设您在 SQL*Plus 或 SQL Developer 中运行它,您有几种方法来声明和使用固定值。 (类似的方法将在其他客户端中可用;PL/SQL 开发人员似乎喜欢这两种方法,至少在命令窗口中,但不确定 Toad 或其他任何东西)。

1) 使用substitution variable:

define id_to_check = 549576015500000109

select txn_timestamp, exception_type
from cut.event
where irn_id = '&id_to_check';

2) 使用bind variable:

variable id_to_check varchar2(18)

exec :id_to_check := '549576015500000109';

select txn_timestamp, exception_type
from cut.event
where irn_id = :id_to_check;

exec 是小型匿名 PL/SQL 块的简写,但除了将值分配给变量的步骤之外,它是纯 SQL,因此查询不需要包装在 begin ... end 中,并且您不必担心选择into 变量。

在任何一种情况下,当脚本运行时,您都可以使用 ID 值 passed as an argument 或 ask for it as part of the script。例如,您可以编写一个query.sql 脚本:

define id_to_check = &1

select txn_timestamp, exception_type
from cut.event
where irn_id = '&id_to_check';

...并运行它:

sqlplus -l -s <user>/<password> @query 549576015500000109

...或作为:

accept id_to_check prompt 'Enter the ID to check: '

select txn_timestamp, exception_type
from cut.event
where irn_id = '&id_to_check';

...并在运行时提示用户输入 ID。

【讨论】:

【参考方案2】:

问题不是“你想把结果放到一个变量中吗”。

在 Oracle 过程的“主体”中,您不能在没有 INTO 子句的情况下使用 SELECT

(其实你可以有,但是在光标中)。

所以

declare
  id_to_check VARCHAR(18);
  event_timestamp cut.event.txn_timestamp%TYPE;
  event_exception cut.event.exception_type%TYPE;

begin
  id_to_check := '549576015500000109';

select 
  txn_timestamp, exception_type
  INTO event_timestamp, event_exception
from cut.event
where irn_id = id_to_check;

end;

注意:如果没有找到结果,这将引发 NO_DATA_FOUND 异常。

你可以管理它

begin
  id_to_check := '549576015500000109';

  BEGIN
  select 
    txn_timestamp, exception_type
    INTO event_timestamp, event_exception
    from cut.event
    where irn_id = id_to_check;

   EXCEPTION WHEN NO_DATA_FOUND THEN 
   --...something
  END

end

【讨论】:

诚然,我是从 Microsoft T-SQL 背景来到 Oracle 的,所以 Oracle 的一些“功能”对我来说仍然是新的。 @user1774673 当然,我的意图不是粗鲁,这只是事实;) 诚然,我是从 Microsoft T-SQL 背景来到 Oracle 的,所以 Oracle 的一些“功能”对我来说仍然是新的。我将如何创建一个具有固定值的变量,以便在我的脚本中进一步使用,而不以某种方式满足 INTO 要求?我仍在编写我的脚本,但被这个问题所困扰。我不需要为变量动态分配任何值 - 我正在尝试为我们的支持团队创建一个脚本,以便在一个地方轻松获取大量信息,而不是查询多个表,而 ID 是关键。跨度> Raphael,非常感谢,但必须这样做:声明 id_to_check VARCHAR(18); event_timestamp cut.event.txn_timestamp%TYPE; event_exception cut.event.exception_type%TYPE;会很麻烦,因为我估计我需要撤回大约 30 列数据。使用视图是不可能的,因为未经客户书面同意,我们无法编辑我们支持的所有 80 个数据库,因此希望将其写入单个查询/脚本中。 @user1774673 好的。我不清楚的是,你想要什么样的结果:你想如何显示结果?【参考方案3】:

你真正的问题不是关于使用变量(你说得对),而是关于从 PL/SQL 块返回游标。

您似乎认为,在过程结束时的一个简单的选择应该以某种方式使其返回结果或至少显示它们。虽然有些数据库是这样工作的,但 Oracle 却没有。如果您希望任何数据离开任何类型的块(如函数或过程),则必须显式传递它们。通常这是通过使用游标引用类型的 in 参数来完成的。

如您所见,没有 into 的 select 在 Oracle 中没有意义。即使您设法使其工作并选择数据,您也无法访问结果。

【讨论】:

以上是关于在 where 子句中使用 Oracle SQL 变量时遇到问题的主要内容,如果未能解决你的问题,请参考以下文章

在oracle中where 子句和having子句中的区别

oracle 形式:pl/sql 中 where 子句中的 max 子句

在 Oracle SQL 中,除了外连接之外,where 子句中的 (+) 运算符的目的是啥?

Oracle SQL Where 子句查找超过 30 天的日期记录

如何在 select 的 where 子句中替换 oracle pl/sql 变量

如何在 oracle sql 数据库中使 WHERE 子句不区分大小写?