【问题标题】:Using bind variables in SQL Plus with more than one row returned?在返回多行的 SQL Plus 中使用绑定变量?
【发布时间】:2012-06-24 17:34:28
【问题描述】:

这是一个愚蠢的问题,但我似乎无法解决它。我有一个在 OCI 程序中引起问题的查询,所以我想在 SQL*Plus 中手动运行它以检查那里是否有任何差异。这是查询:

select e.label as doc_name,
                       e.url,
                       i.item_id,
                       'multi' as form_type
                from cr_items i, cr_extlinks e
                where i.parent_id = :comment_id
                and e.extlink_id = i.item_id
               UNION
                select null as doc_name,
                       utl_raw.cast_to_varchar2(DBMS_LOB.SUBSTR(r.content, 2000, 1))  as url,
                       r.item_id,
                       'single' as form_type
                from cr_revisions r
                where r.revision_id = ( select content_item.get_latest_revision(:comment_id) from dual);
end;

我想将comment_id绑定到值3052753,所以我做了以下:

    DECLARE
     comment_id number := 3052753;
    BEGIN
    select e.label  ,
                           e.url,
                           i.item_id,
                           'multi'  
                    from cr_items i, cr_extlinks e
                    where i.parent_id = :comment_id
                    and e.extlink_id = i.item_id
                   UNION
                    select null  ,
                           utl_raw.cast_to_varchar2(DBMS_LOB.SUBSTR(r.content, 2000, 1))  as url,
                           r.item_id,
                           'single'  
                    from cr_revisions r
                    where r.revision_id = ( select content_item.get_latest_revision(:comment_id) from dual);
    END;
/

这给出了这个错误:

ORA-06550: line 4, column 1:
PLS-00428: an INTO clause is expected in this SELECT statement

现在,我已经很不高兴了,因为我不想从根本上改变这个查询,但无论如何我还是继续前进并想出了这个(INTO 和 UNION 并没有那么顺利地结合在一起):

DECLARE
 comment_id number := 3052753;
 x_label VARCHAR2(50);
 x_url VARCHAR2(500);
 x_item number;
 x_thing VARCHAR2(50);
BEGIN
select label, url, item_id, thing into x_label, x_url, x_item, x_thing from (
select e.label  ,
                       e.url,
                       i.item_id,
                       'multi' as thing  
                from cr_items i, cr_extlinks e
                where i.parent_id = :comment_id
                and e.extlink_id = i.item_id
               UNION
                select null  ,
                       utl_raw.cast_to_varchar2(DBMS_LOB.SUBSTR(r.content, 2000, 1))  as url,
                       r.item_id,
                       'single' as thing 
                from cr_revisions r
                where r.revision_id = ( select content_item.get_latest_revision(:comment_id) from dual)) ;
END;
/

但是现在,当然,因为我返回超过 1 行,所以我得到了完全可预测的结果

ORA-01422: exact fetch returns more than requested number of rows

现在,我可以继续使用游标等,但我的小查询越来越偏离其原始状态。我想做的就是检查查询是否在该 comment_id 值下运行正常。当然,我可以将 comment_id 硬编码到查询中,这样就可以了。但它在 OCI 中也可以正常工作,因此我将在 SQL*PLus 中重现我在 OCI 代码中看到的绑定变量问题。但是,为什么在 SQL*Plus 中做到这一点如此困难呢?我错过了一些非常明显的事情吗?

数据库是 Oracle 10.2.0.1.0 - 64 位,在 Red Hat Enterprise Linux ES 第 4 版(Nahant Update 8)上运行

【问题讨论】:

    标签: oracle sqlplus ora-06550 bind-variables ora-01422


    【解决方案1】:

    类似于@Glenn 的方法,但您可以在 SQL*Plus 中声明一个绑定变量并在普通 SQL 查询中使用它。首先使用var[iable] 命令声明它:

    variable comment_id number;
    

    然后用exec[ute]命令设置,本质上是一个匿名块:

    execute :comment_id := 3052753;
    

    然后使用 :comment_id 引用运行您的原始查询,而不是 BEGINEND

    select e.label as doc_name,
                           e.url,
                           i.item_id,
                           'multi' as form_type
                    from cr_items i, cr_extlinks e
                    where i.parent_id = :comment_id
                    and e.extlink_id = i.item_id
                   UNION
                    select null as doc_name,
                           utl_raw.cast_to_varchar2(DBMS_LOB.SUBSTR(r.content, 2000, 1))  as url,
                           r.item_id,
                           'single' as form_type
                    from cr_revisions r
                    where r.revision_id = ( select content_item.get_latest_revision(:comment_id) from dual);
    

    除了个人喜好之外,我认为这两种方法之间没有太大的功能差异,并且两者都可以在 SQL Developer 中工作(当作为脚本运行时)。当运行从已经使用: 绑定表单的 Pro*C 文件复制的 SQL 时,我发现这更容易,纯粹是因为您根本不需要修改代码。


    顺便说一句,你可以写:

    where r.revision_id = ( select content_item.get_latest_revision(:comment_id) from dual)
    

    没有额外的select,如:

    where r.revision_id = content_item.get_latest_revision(:comment_id)
    

    【讨论】:

    • 谢谢 Alex,我已经尝试过了,但它给出了与我自己的方法相同的错误:PLS-00428: an INTO clause is expected in this SELECT statement
    • 你不能从一个普通的 SQL 块中得到一个 PL/SQL 错误;您正在运行您的查询没有 BEGIN/END 围绕它,对吧?
    • 啊!现在这很有趣。你当然是对的,我确实有一个 BEGIN 和 END 围绕它,因为我得到一个 ORA-00904: : 无效标识符。更有趣的是,如果我按照您的建议更改函数调用,它会起作用!令人印象深刻:-)
    • 现在,是什么让我发疯,直到我弄清楚为什么使用“from dual”的函数调用工作了 10 年,而今天突然停止工作?你知道这种语法是不是最近才加入到 Oracle 中的吗??
    • 更改任何内容都会导致不同的执行计划,并且优化器有机会做出不同的选择并命中/避免其任何错误。我猜您的查询以前没有问题,但是最近的硬解析发生了绊倒,因此出现了您的问题。凡人不应该理解优化器的诡计......
    【解决方案2】:

    你可能想在 sqlplus 中定义一个环境变量,而不是创建一个匿名块:

    DEFINE comment_id = 3052753
    

    然后在您的查询中引用 &comment_id。

    select e.label as doc_name,
                           e.url,
                           i.item_id,
                           'multi' as form_type
                    from cr_items i, cr_extlinks e
                    where i.parent_id = &comment_id
                    and e.extlink_id = i.item_id
                   UNION
                    select null as doc_name,
                           utl_raw.cast_to_varchar2(DBMS_LOB.SUBSTR(r.content, 2000, 1))  as url,
                           r.item_id,
                           'single' as form_type
                    from cr_revisions r
                    where r.revision_id = ( select content_item.get_latest_revision(&comment_id) from dual);
    

    【讨论】:

    • 呵呵,我就是这样一个工具,我在 15 年前就知道了!如此简单,我只是在每一步都深入挖掘。谢谢! :-)
    • 谢谢,我现在更正了(我从上面的匿名块中剪切和粘贴)。
    • Glenn,我要给 Alex 点,因为他的方法我不需要对查询进行任何更改。但我非常感谢您抽出宝贵的时间回复,我给了您一个赞成票。干杯!
    • 谢谢。我也更喜欢 Alex 的回答:)
    猜你喜欢
    • 2012-07-29
    • 1970-01-01
    • 1970-01-01
    • 2021-10-27
    • 2010-09-24
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2021-09-22
    相关资源
    最近更新 更多