我有一张发票表,有数百万的数据。在我的表中,有发票及其客户的第一个和最后一个日期。我的目标是计算发票的月平均价格。例如,我有:
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_DATE
和LAST_DATE
之间的天数。但是我不能这样做。或者有其他方式吗?
答案 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');