【问题标题】:SQL procedure returning too many rowsSQL 过程返回太多行
【发布时间】:2015-11-27 07:52:31
【问题描述】:

我创建了一个以 pid 作为参数并返回该 pid 的每月销售统计信息的过程,它使用两个表 products 和 purchase ,其中购买中的 pid 是引用产品中的 pid 的外键。 该过程构建没有错误,并且仅对单行返回执行良好,否则会给出 too_many_rows 异常 我的程序如下:

set serveroutput on
create or replace procedure try(
p_pid in purchases.pid%type) is
p_pname products.pname%type;
p_date varchar2(10);
p_qty_monthly number(5);
p_amnt_monthly number(7,2);
p_avg_price number(7,2);


begin
select pname, p_time, qty_month, amount_month,(amount_month/qty_month) as avg_sale into p_pname,p_date,p_qty_monthly, p_amnt_monthly, p_avg_price
FROM 
    (select p.pname, to_char(q.ptime,'MON yyyy') p_time, 
    sum(qty) as qty_month, sum(total_price) as amount_month 
    from products p, purchases q
    where p.pid=q.pid
and q.pid= p_pid
group by pname, to_char(q.ptime,'MON yyyy')); 
dbms_output.put_line ('Product name is:'|| p_pname || 'Purchase date is:' || p_date || 'Units sold per month are/is: ' || p_qty_monthly || 'Monthly sale amount: ' || p_amnt_monthly || 'Average sale price is: ' || p_avg_price);
end;
/
show errors

它为某些输入返回不止一行,我怎样才能让它打印所有行而不是给出 too_many_rows 异常?

【问题讨论】:

  • 找不到数据意味着您的选择查询没有返回任何用于处理使用异常块的值。
  • 该错误表明您的结果中没有pname 为“p001”的行。您的 select 语句返回 0 行。如果这是预期的,您可以添加一个异常处理程序来捕获 no_data_found 异常。
  • @JustinCave 查询返回 11 行,其中 1 行与我给出的输入有关,即 p001
  • 您传入的是p_pid。您似乎从未使用该参数是您的代码。您的代码引用了一个从未初始化的局部变量p_pname,因此它为空。没有任何东西等于 NULL 所以,根据定义,查询不能返回任何东西。
  • 您已更改程序,但未更改错误。你还没有得到我假设的no_data_found 异常。我猜想当您尝试将别名为p_time 的字符串存储到名为p_date 的变量中时会发生数据类型转换,该变量似乎被定义为日期而不是varchar2。如果你解决了这个问题,我希望你会得到一个too_many_rows 异常而不是no_data_found 异常。 select into 必须准确返回 1 行。

标签: oracle plsql exception-handling


【解决方案1】:

ORA-01403:未找到数据

您在运行时得到NO DATA FOUND。您的过程代码没有任何问题,但是当您执行它时,SELECT..INTO 查询无法为 过滤谓词 获取行指定。

其中 p.pid=q.pid

您的表中没有 pid='p001'

的行

如果您确定错误,则可以添加no_data_found EXCEPTION 并捕获错误。

EXCEPTION 
   WHEN NO_DATA_FOUND THEN
      <do something>

【讨论】:

  • 对于 p001,2015 年 10 月有销售,当我只运行我嵌入在过程中的 sql 查询时,查询返回不同月份的销售。我怎样才能让我的程序显示它?
【解决方案2】:

如果您在该月没有任何购买,您的查询将不会返回任何数据,因此您收到的错误是由此导致的。 每个查询都需要返回一个结果,否则会出现错误 ORA-1403 No data found。

在您的情况下,您应该使用左连接,因此当该表中没有要连接的记录时,您始终可以从购买中获取记录。因此,在这种情况下,您的总和将为零。

【讨论】:

  • 该产品在 2015 年 10 月有销售,我也尝试了其他产品,当我只运行我嵌入在程序中的 sql 查询时,查询返回不同月份的销售额。我怎样才能让我的程序显示它?
  • 嵌入式 sql 查询返回 11 行,其中 1 行与我给出的输入相关,即 p001
【解决方案3】:

未找到数据意味着您的选择查询未返回任何“p001”p_id 值。还要确保您的选择查询一次只返回一行,否则会引发错误。因为一个变量一次只能保存一个值。

create or replace procedure m_pro(
        p_pid in products.pid%type) is
        p_pname products.pname%type;
        p_date purchases.ptime%type;
        p_qty_monthly purchases.qty%type;
        p_amnt_monthly purchases.total_price%type;
        p_avg_price purchases.total_price%type;


    begin
    select pname, p_time, qty_month, amount_month,(amount_month/qty_month) as avg_sale into p_pname,p_date,p_qty_monthly, p_amnt_monthly, p_avg_price
    FROM 
        (select p.pname, to_char(q.ptime,'MON yyyy') p_time, 
        sum(qty) as qty_month, sum(total_price) as amount_month 
        from products p, purchases q
        where p.pid=q.pid
    group by pname, to_char(q.ptime,'MON yyyy')) 
    where pname=p_pname;
    dbms_output.put_line ('Product name is:'|| p_pname || 'Purchase date is:' || p_date || 'Units sold per month are/is: ' || p_qty_monthly || 'Monthly sale amount: ' || p_amnt_monthly || 'Average sale price is: ' || p_avg_price);
    EXCEPTION
    WHEN no_data_found THEN
      dbms_output.Put_line ('No values returned');

    end;
    /

只需在结束语句之前添加异常块。

编辑:您的带有 p_pid 检查的选择查询是

   select pname, p_time, qty_month, amount_month,(amount_month/qty_month) as avg_sale 
        FROM 
            (select p.pname, to_char(q.ptime,'MON yyyy') p_time, 
            sum(qty) as qty_month, sum(total_price) as amount_month 
            from products p, purchases q
            where p.pid=q.pid and p.pid=(some value) -- in procedure p.pid=p_pid
        group by pname, to_char(q.ptime,'MON yyyy')) 
       -- where pname=p_pname remove where pname=p_name

【讨论】:

  • 您有一个语法错误,这将引发编译错误。
  • @LalitKumarB 编辑了帖子并删除了额外的结尾。谢谢,请告知任何错误。
  • 对于 p001,2015 年 10 月有销售,当我只运行我嵌入在过程中的 sql 查询时,查询返回不同月份的销售。我怎样才能让我的程序显示它?
  • 查询返回 11 行,其中 1 行与我给出的输入相关,即 p001 @Tarun
  • @Tarun 我也在那个地方尝试了 pid,但是它给出了构建错误作为无效标识符,我应该在那里使用什么?
【解决方案4】:

在我看来,您应该使用 Ref 游标来避免处理 No Data Found 或 Too many Rows 异常的任何担忧。下面sn-p会和你打招呼。

CREATE OR REPLACE PROCEDURE m_pro(
    p_pid IN products.pid%type,
    p_lst OUT sys_refcursor) -- Use ref cursor to avoid no data found or too many rows exception
IS
--  p_pname products.pname%type;
--  p_date purchases.ptime%type;
--  p_qty_monthly purchases.qty%type;
--  p_amnt_monthly purchases.total_price%type;
--  p_avg_price purchases.total_price%type;
BEGIN
  OPEN p_lst FOR 
  SELECT pname, 
  p_time, 
  qty_month, 
  amount_month, 
  (amount_month/qty_month)
AS
  avg_sale FROM
  (SELECT p.pname,
    TO_CHAR(q.ptime,'MON yyyy') p_time,
    SUM(qty)         AS qty_month,
    SUM(total_price) AS amount_month
  FROM products p,
    purchases q
  WHERE p.pid=q.pid
  GROUP BY pname,
    TO_CHAR(q.ptime,'MON yyyy')
  ) WHERE P.pid=p_pid;
END; 

【讨论】:

  • 我还要在 IS 之后声明变量吗?并给出 p_lst 中的名称?当我执行该过程时,第二个参数是什么?
  • 这取决于您在执行 sp 后如何操作结果。如果您只是希望输出显示,那么参考光标就可以了。
  • 如果您需要在 sp 执行后操作数据,那么我们需要 stcik to INTO 子句,如您的帖子所示
猜你喜欢
  • 2014-07-23
  • 1970-01-01
  • 2011-12-29
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多