使用 PostgreSQL PL/pgSQL 在 For 循环中添加月份

Posted

技术标签:

【中文标题】使用 PostgreSQL PL/pgSQL 在 For 循环中添加月份【英文标题】:Add Months in a For Loop using PostgreSQL PL/pgSQL 【发布时间】:2021-09-15 15:25:03 【问题描述】:

我正在学习 for 循环并尝试使用 PostgreSQL 创建一个 PL/pgSQL 块,该块将生成一个付款时间表。此循环运行 12 个月,直到余额为 0,并且每个月都会显示到期日期。

这是我目前所拥有的,但月份部分没有添加到 for 循环中,它只添加了一次。

DO $$ 
DECLARE
    start_date DATE := '01-Jan-2021';
    payment_due_date DATE;
    due_date VARCHAR(25);
    mon_pay_amt NUMERIC := 10;
    total_mon_amt NUMERIC := 12;
    bal_num NUMERIC :=0;

BEGIN
bal_num := mon_pay_amt * total_mon_amt;
due_date := start_date; 
RAISE NOTICE 'Total Amount due in 12 Months: %', to_char(bal_num, '$999.99');
FOR i IN 1..total_mon_amt LOOP
    bal_num := bal_num - mon_pay_amt;
    payment_due_date := start_date + INTERVAL '1 MONTH';
    RAISE NOTICE 'Payment Number: %', i ||' '|| 'Due Date: ' ||payment_due_date|| ' Payment Amount : ' || to_char(mon_pay_amt, '$99.99') ||' '||
    'Balance ' || to_char(bal_num, '$999.99');

END LOOP;
END $$;

【问题讨论】:

那是因为你不断将'1 month' 添加到start_date,它被固定为'01-Jan-2021'。您需要在循环中使用i 计数器。比如:start_date + INTERVAL i::varchar || ' ' || MONTH'. 那么你有答案了吗? 【参考方案1】:

会这样工作:

DO
$$ 
DECLARE
   start_date date := '2021-01-01';  -- always use ISO date format
   payment_due_date date := start_date;
   mon_pay_amt numeric := 10;
   mon_pay_amt_text text :=  to_char(mon_pay_amt, '$90.99');
   total_mon_amt int := 12;
   bal_num numeric := mon_pay_amt * total_mon_amt;
BEGIN
   RAISE NOTICE 'Total Amount due in 12 Months: %', to_char(bal_num, '$999.99');
   FOR i IN 1 .. total_mon_amt LOOP
      bal_num := bal_num - mon_pay_amt;
      RAISE NOTICE '%', format('Payment Number: %s Due Date: %s Payment Amount: %s Balance %s'
                             , i
                             , payment_due_date
                             , mon_pay_amt_text
                             , to_char(bal_num, '$990.99'));
      payment_due_date := payment_due_date + interval '1 month';  -- increment after?
   END LOOP;
END
$$;

但考虑使用 generate_series() 而不是循环的基于集合的方法:

DO
$$ 
DECLARE
   start_date date := '2021-01-01';
   payment_due_date date := start_date;
   mon_pay_amt numeric := 10;
   mon_pay_amt_text text :=  to_char(mon_pay_amt, '$99.99');
   total_mon_amt int := 12;
   bal_num numeric := mon_pay_amt * total_mon_amt;
BEGIN
   RAISE NOTICE '%'
   , (SELECT 'Total Amount due in 12 Months: ' || to_char(bal_num, '$999.99') || E'\n'
          || string_agg(format('Payment Number: %s Due Date: %s Payment Amount: %s Balance: %s'
                             , i
                             , payment_due_date + interval '1 month' * (i-1)
                             , mon_pay_amt_text
                             , to_char(bal_num - mon_pay_amt * i, '$990.99'))
                        , E'\n')                     
      FROM   generate_series(1, total_mon_amt) i
      );
END
$$;

【讨论】:

以上是关于使用 PostgreSQL PL/pgSQL 在 For 循环中添加月份的主要内容,如果未能解决你的问题,请参考以下文章

PostgreSQL-PL/pgSQL控制结构

如何在 PostgreSQL、PL/pgSQL 上执行匿名代码块切换 CASE 语句?

是否可以在 Spring Data JPA Repository 的 @Query 注释中使用 PostgreSQL 匿名块(PL/pgSQL)?

有没有为 PostgreSQL 开发的 PL/pgSQL 免费环境?

PostgreSQL vs Oracle:PL/pgSQL 的“编译时”检查

PostgreSQL:列名到数组 PL/pgSQL