【问题标题】:PostgreSQL select sum inside procedurePostgreSQL在过程中选择总和
【发布时间】:2021-11-23 18:54:48
【问题描述】:

我想要一个程序来检查哪个买家花了超过 1600 美元,然后我想打印出他们的信息,这样我就可以给他们寄一张礼品卡。 我收到错误:SQL 错误 [42601]:错误:查询没有结果数据的目的地 当我调用这个程序时:

create or replace procedure bookstore.procedure1 () 
language plpgsql
as $$
declare 
    i integer := 0;
    temp_price numeric;
    temp_sum numeric;
    temp_foreign_key integer;
    number_of_buyers integer := (select count(*) from bookstore.buyer);
    
begin
    
    while i < number_of_buyers loop
        
        select sum (price) as temp_sum from bookstore.receipt where id_buyer = i;
        
        if temp_sum > 1600 then
            select id_buyer, name, surname, adress from bookstore.buyer where id_buyer = i;
        end if;
        i := i+1;
        
    end loop;

end

$$;

问题在于 选择 sum (price) as temp_sum... 行。我在 MySQL 中有类似的过程,它可以工作。例如,我尝试使用 id_buyer = 20 运行该行并且它有效。应该怎么改?

这是我关于stackoverflow的第一个问题,希望可以理解。

【问题讨论】:

    标签: sql postgresql select stored-procedures plpgsql


    【解决方案1】:

    让 SQL 完成提供数据的所有工作。这可以在一个语句中完成。

    select buy.buy_id
         , buy.name  
         , buy.address 
         , buy.city      
         , buy.postal_code 
         , pur.purchases
      from buyers   buy
      join ( select inv.buy_id 
                  , sum(inv.amount)  purchases
               from invoices inv
              group by buy_id
              having sum(inv.amount) >= 1600.00          
           ) pur
        on (pur.buy_id = buy.buy_id) ;
    

    如果您必须有一个存储程序,那么将上述查询包装在一个返回表的 SQL 函数中。然后从函数中选择。

    create or replace 
    function preferred_buyers()
      returns table ( buy_id   integer  
                    , name     text 
                    , address  text
                    , city     text
                    , postal_code text
                    , purchases numeric(7,2)
                    ) 
       language sql
    as $$
        select buy.buy_id
             , buy.name  
             , buy.address 
             , buy.city      
             , buy.postal_code 
             , pur.purchases
          from buyers   buy
          join ( select inv.buy_id 
                      , sum(inv.amount)  purchases
                   from invoices inv
                  group by buy_id
                  having sum(inv.amount) >= 1600.00          
               ) pur
            on (pur.buy_id = buy.buy_id) ;
    $$;  
    
    select * from preferred_buyers();
    

    以上都不处理打印任务。这不是 SQL 非常擅长的。实际上它不能这样做。打印需要编程语言扩展;对于 Postgres,它是 plpgsql。还要意识到至少在生产环境中无法进行任何打印;它将在数据库服务器上。在演示文稿管理器(应用程序)中处理您的打印。

    【讨论】:

      【解决方案2】:

      在plpgsql SELECT 语句中必须有一个receiver。 您必须使用 INTO 重定向 SELECT 输出或使用直接的矫揉造作

      --Fist version
      SELECT SUM(price) FROM bookstore.receipt WHERE id_buyer = i INTO temp_sum;
      --Second version, keep surrounding parenthesis
      temp_sum = (SELECT SUM(price) FROM bookstore.receipt WHERE id_buyer = i);
                      
      

      关于你的循环,你应该使用更高效和安全的东西

      DECLARE
          temp_sum         NUMERIC;
          v_buyer          bookstore.BUYER;
      BEGIN
      
          FOR v_buyer IN SELECT * FROM bookstore.buyer LOOP
              --Use coalesce to manage empty result
              temp_sum = (SELECT coalesce(SUM(price), 0) FROM bookstore.receipt WHERE id_buyer = v_buyer.id);
      
              IF temp_sum > 1600 THEN
                  -- Your business logic
              END IF;
      
          END LOOP;
      END
      

      如果您的数据集很大,最好使用光标

      DECLARE
          temp_sum NUMERIC;
          v_buyer_cursor CURSOR FOR SELECT * FROM bookstore.buyer;
          v_buyer  bookstore.BUYER;
      BEGIN
      
          FOR v_buyer IN v_buyer_cursor LOOP
      
              temp_sum = (SELECT COALESCE(SUM(price), 0) FROM bookstore.receipt WHERE id_buyer = v_buyer.id);
      
              IF temp_sum > 1600 THEN
                  -- Your business logic
              END IF;
              
          END LOOP;
      END
      

      【讨论】:

        【解决方案3】:

        您可能需要添加 return 语句

        函数创建定义SQL中,必须有一行写成RETURNS integer/text

        试试-

        language plpgsql
        as $$
        declare 
            i integer := 0;
            temp_price numeric;
            temp_sum numeric;
            temp_foreign_key integer;
            number_of_buyers integer := (select count(*) from bookstore.buyer);
            
        begin
            
            while i < number_of_buyers loop
                
                select sum (price) as temp_sum from bookstore.receipt where id_buyer = i;
                
                if temp_sum > 1600 then
                    select id_buyer, name, surname, adress from bookstore.buyer where id_buyer = i;
                end if;
                i := i+1;
                
            end loop;
        
        return 1; 
        end
        $$;
        

        否则,您可以使用 CREATE OR REPLACE FUNCTION your_function ...

        删除 RETURNS 文本/整数的初始语句

        【讨论】:

        • 第一行以前不可见,我现在更正了,抱歉。这是一个程序。一个函数必须有一个 RETURN 语句(带有一些值),但您不能在过程中使用 RETURN 返回值。你可以只写return;并停止该程序。因此,如果我尝试您建议的代码,则会出现错误,因为 RETURN 有一个参数。
        猜你喜欢
        • 2013-11-30
        • 2010-10-03
        • 1970-01-01
        • 1970-01-01
        • 2020-08-01
        • 2015-11-24
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多