如何在ORACLE(Varray& loop)中计算发票的月平均价格

时间:2017-03-06 07:38:06

标签: sql oracle

我有一张发票表,有数百万的数据。在我的表中,有发票及其客户的第一个和最后一个日期。我的目标是计算发票的月平均价格。例如,我有:

CUSTOMER_ID     INVOICE_ID    FIRST_DATE     LAST_DATE     AMOUNT_OF_INVOICE
9876543          1a           1 Jan 2017     17 Jan 2017         32$
9876543          1b          17 Jan 2017     10 Feb 2017         72$
9876543          1c          10 Feb 2017     7 March 2017        100$
9876543          1d          7 March 2017    1 April 2017        25$
9870011          2a           1 Jan 2017     10 Jan 2017         18$
9870011          2b          10 Jan 2017     10 Feb 2017         62$
9870011          2c          10 Feb 2017     1 April 2017        50$


my target is:

CUSTOMER_ID        MONTH         MONTHLY_AVERAGE_PRICE
9876543         January 2017         77$                 (=16x2+15x3)
9876543         February 2017        103$                (=9x3+19x4)
9876543         March 2017           49$                 (=6x4+25x1)
9870011         January 2017         62$                 (=9x2+22x2)
9870011         February 2017        37$                 (=9x2+19x1)
9870011         March 2017           31$                 (=31x1)

例如,我通过以下方式计算77 $(=16x2+15x3): INVOICE_ID为1a的第一张发票有2017年1月1日至2017年1月17日的16天(不包括1月17日)。发票的价格是32美元。因此,一天的平均价格是32/16 = 2 $。第二张发票为1b,2017年1月17日至2017年2月10日为期24天。因此,每日平均消费为3美元。 1月份的发票部分为15天(1月17日至1月31日,包括1月31日)。总而言之,1月平均消费:16x2 $ + 15x3 $ = 77 $。

我认为,我必须使用varray存储数月的数据,我必须使用循环来查找FIRST_DATELAST_DATE之间的天数。但是我不能这样做。或者有其他方式吗?

2 个答案:

答案 0 :(得分:0)

Oracle查询

WITH month_invoices ( c_id, i_id, first_date, last_date, month_start, month_end, amount )
AS (
  SELECT customer_id,
         invoice_id,
         first_date,
         last_date,
         first_date,
         LEAST( ADD_MONTHS( TRUNC( first_date, 'MM' ), 1 ), last_date ),
         amount_of_invoice
  FROM   your_table
UNION ALL
  SELECT c_id,
         i_id,
         first_date,
         last_date,
         month_end,
         LEAST( ADD_MONTHS( month_end, 1 ), last_date ),
         amount
  FROM   month_invoices
  WHERE  month_end < last_date
)
SELECT c_id AS customer_id,
       TRUNC( month_start, 'MM' ) AS month,
       SUM( amount * ( month_end - month_start ) / ( last_date - first_date ) )
         AS average_monthly_price
FROM   month_invoices
GROUP BY c_id, TRUNC( month_start, 'MM' )
ORDER BY customer_id, month;

<强>输出

CUSTOMER_ID MONTH      AVERAGE_MONTHLY_PRICE
----------- ---------- ---------------------
    9876543 2017-01-01                    77
    9876543 2017-02-01                   103
    9876543 2017-03-01                    49
    9870011 2017-01-01                    62
    9870011 2017-02-01                    37
    9870011 2017-03-01                    31

答案 1 :(得分:0)

这就是我想出来的。
内部查询为每张发票的每一天创建一行 外部查询总结了它们 它假定发票最长只有999天。

select customer_id, month, sum(average_cost_per_day) average_cost_per_day
from (
  select max(customer_id) customer_id,
         invoice_id,
         to_char(first_date + n-1, 'MONTH YYYY') month,
         count(1)*max(amount_of_invoice)/max(last_date-first_date) average_cost_per_day
  from your_table
  inner join (
    select level n
    from dual
    connect by level <= 1000
  )
  on (first_date + n-1 < last_date)
  group by invoice_id, to_char(first_date + n-1, 'MONTH YYYY')
)
group by customer_id, month
order by customer_id desc, to_date(month,'MONTH YYYY');