2017-03-06 17 views
0

我有一個發票表,並有數百萬的數據。在我的表格中,有發票和客戶的第一個和最後一個日期。我的目標是計算髮票的月平均價格。比如我有:如何計算ORACLE中發票的月平均價格(Varray&循環)

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有16天,從2017年1月一日至1月17日2017年(不incuding 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之間的天數。但是我做不到。還是以其他方式存在?

+0

如何獲得77 $。? 。和什麼意思(= 16.2 + 15.3)?你的問題不清楚.. – scaisEdge

+0

哦,對不起。 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月的平均消費:16.2美元+ 15.3美元= 77美元。現在清楚嗎?如果沒有,我可以解釋更多..謝謝你的幫助 – Abdullah

回答

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 
+0

謝謝。這段代碼很好:)我要求理解。我無法理解的部分:UNION ALL SELECT C_ID, i_id, FIRST_DATE, LAST_DATE, MONTH_END, LEAST(ADD_MONTHS(MONTH_END,1),LAST_DATE) 量 FROM month_invoices WHERE MONTH_END Abdullah

+0

@Abdullah它是一個遞歸的子查詢分解子句(也稱爲遞歸CTE)。頂部部分'SELECT ... FROM your_table'生成原始表中每行的第一個月的數據,然後第二部分'UNION ALL SELECT ... FROM month_invoices'遞歸以生成每行的剩餘月份原來的桌子。最後一位'SELECT ... FROM month_invoices GROUP BY ...'然後每個月總計一次。 – MT0

+0

謝謝你的幫助。這對我來說是很好的信息。再次感謝你 – Abdullah

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');