簡體   English   中英

Oracle SQL 循環填充未來日期

[英]Oracle SQL Loop to fill future dates

對此有疑問-我計划在未來幾周內使用前幾年的魔獸世界運動(因此我可以獲得全年的預測)-通常這對業務很有效,所以我正在使用它。

我想要做的是使用以下作為實際收入數字:

塊引用

並使用前一年的一周一周的變動來填充未來的幾周,例如:

在此處輸入圖像描述

所以我想將第 4 周的實際值乘以第 5 周的倍數 (1.125) 以獲得第 5 周的預測值 (15,187.5),然后將第 6 周的 15,187.5 乘以 0.972 直到第 8 周:

在此處輸入圖像描述

有人對代碼有任何想法嗎?

謝謝

您可以為此使用 model 子句。 可能有一種更有效/更清潔的方式,但假設您有一張包含年、周和收入的表格,那么:

select year, week, revenue
from your_table
model
  dimension by (year, week)
  measures (revenue, 0 week_chg)
  rules upsert sequential order (
    week_chg[any, any] =
      revenue[cv(year) - 1, cv(week)]/revenue[cv(year) - 1, cv(week) - 1],
    revenue[any, any] =
      coalesce(
        revenue[cv(), cv()],
        round(revenue[cv(year), cv(week) - 1] * week_chg[cv(year), cv(week)], 2)
      )
  )

產生:

星期 收入
2021 1 1000
2021 2 2000
2021 3 3000
2021 4 8000
2021 5 9000
2021 6 8750
2021 7 9500
2021 8 10000
2022 1 10000
2022 2 12000
2022 3 15000
2022 4 13500
2022 5 15187.5
2022 6 14765.63
2022 7 16031.26
2022 8 16875.01

db<>小提琴

這將依次應用兩個規則。 首先:

week_chg[any, any] =
      revenue[cv(year) - 1, cv(week)]/revenue[cv(year) - 1, cv(week) - 1]

計算出上一年的周變化值 - 一年前和同一周的收入除以一年前和一周前的收入。

然后

    revenue[any, any] =
      coalesce(
        revenue[cv(), cv()],
        round(revenue[cv(year), cv(week) - 1] * week_chg[cv(year), cv(week)], 2)

將當前維度的收入設置為實際收入值(如果有); 否則是前一周的收入(關鍵是,它可能只是自己計算出來的)乘以匹配的周變化值。 然后將該值四舍五入到小數點后兩位,這似乎是您想要的。

(由於舍入差異,最后兩個結果與您的示例略有不同。如果week_chg舍入到小數點后 6 位,則 2002 年第 8 周的結果正好為 16875,但第 7 周和第 6 周則不同。)

如果您分別需要它們,小提琴有一個顯示兩個值的中間結果。

假設你有桌子:

CREATE TABLE this_year (week, revenue) AS
SELECT 1, 10000 FROM DUAL UNION ALL
SELECT 2, 12000 FROM DUAL UNION ALL
SELECT 3, 15000 FROM DUAL UNION ALL
SELECT 4, 13500 FROM DUAL;

CREATE TABLE last_year (week, revenue) AS
SELECT 1,  5000 FROM DUAL UNION ALL
SELECT 2,  6000 FROM DUAL UNION ALL
SELECT 3,  7000 FROM DUAL UNION ALL
SELECT 4,  8000 FROM DUAL UNION ALL
SELECT 5,  9000 FROM DUAL UNION ALL
SELECT 6,  8750 FROM DUAL UNION ALL
SELECT 7,  9500 FROM DUAL UNION ALL
SELECT 8, 10000 FROM DUAL;

然后您可以使用MODEL子句:

SELECT week,
       revenue
FROM   (
  SELECT ly.week AS week,
         ly.revenue AS ly_revenue,
         ty.revenue AS ty_revenue
  FROM   last_year ly
         LEFT OUTER JOIN this_year ty
         ON (ly.week = ty.week)
)
MODEL
  DIMENSION BY (week)
  MEASURES (
    ly_revenue,
    ty_revenue,
    0 AS ly_multiplier,
    0 AS revenue
  )
  RULES AUTOMATIC ORDER (
    revenue[1]      = COALESCE(
                        ty_revenue[1],
                        ly_revenue[1]
                      ),
    revenue[week>1] = COALESCE(
                        ty_revenue[cv()],
                        revenue[cv()-1] * ly_revenue[cv()]/ly_revenue[cv()-1]
                      )
  );

哪個輸出:

星期 收入
1 10000
2 12000
3 15000
4 13500
6 14765.625
5 15187.5
7 16031.25
8 16875

db<> 在這里擺弄

首先請看一下去年的每周變化數。 當您將第 4 周的收入乘以 8000 x 第 5 周的變化 1.125 = 9000 時,您將獲得第 5 周的收入。 當您將第 5 周和第 6 周的變化相乘時 = 1.125 x 0.972222 = 1,093749。 然后,當您將此數字乘以第 4 周的收入 8000 = 時,您將獲得第 6 周的收入 8750。

所以類似的邏輯,你需要保留你知道的最新記錄。 所以在這種情況下,今年是第 4 周。 然后乘以每周變化值。 為此,讓我們從數學中獲得幫助。 您可以將每個值的對數相加,然后取結果的指數。 然后你得到每周乘以變化的值,然后將結果乘以收入。

select * 
 from (
    select '1' as week, 10000 as revenue 
     union all 
    select '2' as week, 12000 as revenue 
     union all 
    select '3' as week, 15000 as revenue 
     union all 
    select '4' as week, 13500 as revenue 
   )m
  union all
  -- future 
  select  
         ly.week,
         (m.revenue * exp(sum(log(ly2.week_chg)))) as revenue_future
    from (
          select '4' as week, 13500 as revenue -- you can get latest record via rownum, i will share query below 
         )m     
     join (
           select '4' as week, 8000 as revenue_ly, null as week_chg
            union all 
           select '5' as week, 9000 as revenue_ly, 1.125 as week_chg 
            union all 
           select '6' as week, 8750 as revenue_ly, 0.972222 as week_chg
            union all 
           select '7' as week, 9500 as revenue_ly, 1.085714 as week_chg
            union all 
           select '8' as week, 10000 as revenue_ly, 1.052632 as week_chg 
          )ly   
        on ly.week > m.week
      join (
           select '4' as week, 8000 as revenue_ly, null as week_chg
            union all 
           select '5' as week, 9000 as revenue_ly, 1.125 as week_chg 
            union all 
           select '6' as week, 8750 as revenue_ly, 0.972222 as week_chg
            union all 
           select '7' as week, 9500 as revenue_ly, 1.085714 as week_chg
            union all 
           select '8' as week, 10000 as revenue_ly, 1.052632 as week_chg 
         )ly2
       on ly.week >= ly2.week
    where 1 = 1
    group by ly.week 

從主表獲取最新記錄:

   select week, revenue
     from (
       select m.*,
              row_number() over(partition by 1 order by week desc) rn
         from (
                select '1' as week, 10000 as revenue 
                 union all 
                select '2' as week, 12000 as revenue 
                 union all 
                select '3' as week, 15000 as revenue 
                 union all 
                select '4' as week, 13500 as revenue 
               )m 
         )dt
    where 1 = 1
      and rn = 1 

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM