【问题标题】:Subtraction of inventory from Demand in BigQuery everday and adding new inventory从 BigQuery 中的每日需求中减去库存并添加新库存
【发布时间】:2021-11-23 12:59:05
【问题描述】:

我的数据如下所示:

date sku inventory_added demand
22nd Nov 2021 XYZ 70 18
23rd Nov 2021 XYZ 0 18
24th Nov 2021 XYZ 0 50
25th Nov 2021 XYZ 0 15
26th Nov 2021 XYZ 80 30
27th Nov 2021 XYZ 0 20
28th Nov 2021 XYZ 0 15
29th Nov 2021 XYZ 0 20
30th Nov 2021 XYZ 0 10
1st Dec 2021 XYZ 100 40
2nd Dec 2021 XYZ 0 10

我想使用 BigQuery SQL 创建一个名为 solution 的新列,在第一行,即 2021 年 11 月 22 日,我希望公式为 - inventory_added - demand。 这将给我solution 的第一行值将是 52。

现在我不能做的是从第二行开始: 所以,接下来是52 (remaining inventory from previous day) + 0 (inventory_added on 23rd Nov 2021) - 18 (demand on 23 Nov 2021)。这等于 34。

类似地转到下一行,即 11 月 24 日: solution 中的值将是 34 + 0 - 50 = -16。现在既然是负数,就应该设为0。

我试过了 - MAX(solutions, 0)

结果将如下所示:

date sku inventory_added demand solution
22nd Nov 2021 XYZ 70 18 52
23rd Nov 2021 XYZ 0 18 34
24th Nov 2021 XYZ 0 50 0
25th Nov 2021 XYZ 0 15 0
26th Nov 2021 XYZ 80 30 50
27th Nov 2021 XYZ 0 20 30
28th Nov 2021 XYZ 0 15 15
29th Nov 2021 XYZ 0 20 0
30th Nov 2021 XYZ 0 10 0
1st Dec 2021 XYZ 100 40 60
2nd Dec 2021 XYZ 0 10 50

我不确定 BigQuery 是否可以实现这一点,但欢迎提出所有建议。

谢谢!

【问题讨论】:

    标签: sql google-bigquery bigquery-udf


    【解决方案1】:

    如果没有条件“它是否定的,它应该设为 0”,您可以使用 SUM() function 的窗口(在 BigQuery 术语中 - 分析)变体:

    SELECT *, 
           SUM(inventory_added - demand) OVER (PARTITION BY sku ORDER BY date) AS solution
    FROM source_table
    

    在这种情况下,输出变为迭代,您必须使用递归 CTE(如果在 BigQuery 中可用)或迭代存储过程。


    我看到递归 CTE 在 BigQuery 中不可用...您能否提供一个伪代码作为存储过程的起点? – 山塔努耆那教

    CREATE PROCEDURE procname()
    BEGIN
        CREATE temptable;
        OPEN CURSOR FOR SELECT * FROM datatable ORDER BY date;
        SET @solution = 0;
        FETCH CURSOR INTO @date, @sku, @inventory_added, @demand;
        LOOP    ​
           ​ SET @solution = GREATEST(@solution + @inventory_added - @demand, 0);
           ​ INSERT INTO temptable VALUES (@date, @sku, @inventory_added, @demand, @solution);
            FETCH CURSOR INTO @date, @sku, @inventory_added, @demand;
        UNTIL NO_ROWS_IN_CURSOR END LOOP;
        SELECT * FROM temptable;
        DROP temptable;
    END
    

    【讨论】:

    • 感谢@Akina,但是,我发现 BigQuery 中没有递归 CTE,而且我对“迭代存储过程”没有太多经验。你能提供一个伪代码作为存储过程的起点吗?再次非常感谢。
    • @ShantanuJain 伪代码(类似于 MySQL 语法)添加。
    • 非常感谢@Akina,我现在就试试。 :)
    【解决方案2】:

    作为一个选项 - 考虑使用最近引入的FOR...IN Loop

    declare result int64;
    declare prev_sku string;
    
    create temp table results as (select *, 0 as solution from your_table where false);
    
    set (result, prev_sku) = (0, '');
    for record in (select *, parse_date('%d %B %Y', regexp_replace(date, r'(\d*)(\w*)( \w{3} \d{4})', r'\1 \3')) dt from your_table order by sku, dt) do
      if record.sku != prev_sku then set result = 0; end if;
      set result = result + record.inventory_added - record.demand;
      if result < 0 then set result = 0; end if;
      insert into results values(record.date, record.sku, record.inventory_added, record.demand, result);
      set prev_sku = record.sku;  
    end for;
    select * from results 
    order by sku, parse_date('%d %B %Y', regexp_replace(date, r'(\d*)(\w*)( \w{3} \d{4})', r'\1 \3'));   
    

    如果应用于您问题中的样本数据 - 输出是

    注意:在提供预期结果时 - 显然这将非常缓慢(与任何基于光标的解决方案一样) - 因此在适用于学习时 - 我认为不适合实际生产使用

    【讨论】:

    • 你试过了吗?对你有用吗?
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2015-08-24
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2016-06-30
    相关资源
    最近更新 更多