【问题标题】:SELECT INTO STATEMENT INSIDE A SQL PROCEDURE THROWING AN ERRORSELECT INTO 语句在 SQL 过程中引发错误
【发布时间】:2022-01-03 16:27:24
【问题描述】:

您好,我想将 select 语句的值存储到变量中,然后在过程中使用该变量更新我的表,但出现错误。我仍然不知道它只返回一列然后也存在以下错误。 精确提取返回的行数超过了请求的行数。

这是演示代码的示例。任何人都可以给我一个替代方法,我可以在这里做些什么来使它工作,因为我有很多这样的 plsql 语句来填充表列

create or replace procedure pcountry (country IN Varchar) is
var_date Date;
begin

select date into var_date from countrytable where country=country;

update newtable
set date=var_date
where country=country
commit;

end pcountry;

【问题讨论】:

    标签: sql oracle stored-procedures plsql oracle11g


    【解决方案1】:

    正如在其他答案中所解释的那样,问题在于,在 country = country 这样的条件下,期望 country 在相等的两侧表示不同的东西是没有意义的标志。名称country 具有多个含义 - 然后应用一组规则来确定每次使用该名称时要接受的含义。这通常是名称存在的最狭窄的上下文(“范围”);在这种情况下,该名称存在于 SQL 语句中引用的表中,这就是 country 的含义。

    一个解决方案很简单 - 为过程中使用的参数使用不同的名称。这也显示在其他答案中。

    还有另一种解决方案。如果您的过程已经很长,它可能更适合使用类似country 的参数名称,现在您需要在需要在 SQL 语句中使用该名称的地方添加一些代码。到处更改参数名称会非常耗时。令人高兴的是,PL/SQL 可以理解限定名。 country(在where 子句中使用它)是查询中引用的表的列名。但是如果你在右边写pcountry.country限定变量名和过程名,就不会再出现混淆了。

    ... where country = pcountry.country
    

    将获得与此线程中其他建议的答案相同的结果。右侧是来自过程的参数或变量,而不是表中的列名。

    请注意,您也可以限定左侧:

    ... where countrytable.country = pcountry.country
    

    也许这对未来的读者来说会更清楚。

    但是,这不会有帮助:

    ... where countrytable.country = country
    

    你知道为什么吗?

    【讨论】:

      【解决方案2】:

      不要使用与列相同的名称来命名 PL/SQL 变量/参数。 SQL 引擎将在本地 SQL 范围内查找 country 值,而不是外部 PL/SQL 范围,因此 country=country (假设非NULL 值)与 1=1 相同,您将匹配所有行。

      假设每个country 都是唯一的:

      create or replace procedure pcountry (
        v_country IN COUNTRY_TABLE.COUNTRY%TYPE
      ) is
        var_date COUNTRY_TABLE."DATE"%TYPE;
      begin
        select "DATE"
        into var_date
        from countrytable
        where country=v_country;
      
        update newtable
        set "DATE"=var_date
        where country=v_country
      end pcountry;
      /
      

      另外,DATE 是一个保留字,不能将 is 用作不带引号的标识符。

      您可以使用MERGE 将其组合成一条 SQL 语句:

      CREATE PROCEDURE pcountry (
        v_country IN COUNTRY_TABLE.COUNTRY%TYPE
      ) is
        var_date COUNTRY_TABLE."DATE"%TYPE;
      BEGIN
        MERGE INTO newtable n
        USING (SELECT *
               FROM   countrytable
               WHERE  country = v_country) c
        ON (c.country = n.country)
        WHEN MATCHED THEN
          UPDATE
          SET "DATE" = c."DATE";
      END pcountry;
      /
      

      【讨论】:

        【解决方案3】:

        跳过select,切换到merge

        CREATE OR REPLACE PROCEDURE pcountry (par_country IN varchr2)
        IS
        BEGIN
           MERGE INTO newtable n
                USING countrytable c
                   ON (c.country = n.country)
           WHEN MATCHED
           THEN
              UPDATE SET n.date_column = c.date_column
           WHERE n.country = par_country;
        END;
        /
        

        【讨论】:

          【解决方案4】:

          您需要更改过程输入参数的名称,因为您的表中有一个同名的列。 Oracle 正在解释您的 where 子句 where country = countrywhere 1 = 1,这始终是正确的。所以它返回更多行而不是一行。

          create or replace procedure pcountry (country_in IN Varchar) is
          var_date Date;
          begin
          
          select date into var_date from countrytable where country = country_in ;
          
          update newtable
          set date=var_date
          where country= country_in 
          commit;
          
          end pcountry;
          
          

          【讨论】:

          • 感谢您的及时回复。有用。我想知道它有什么问题,但是当映射演示代码时答案就出来了。
          • 不客气。
          猜你喜欢
          • 1970-01-01
          • 2014-02-07
          • 2012-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 2012-10-18
          相关资源
          最近更新 更多