Как рассчитать средний запас на ежемесячной основе для каждого продукта и организации? - PullRequest
0 голосов
/ 07 мая 2019

У меня есть таблица с некоторыми записями об инвентаризации на складе. Есть сценарии для их генерации.

create table TB_GOODS
(
  id          NUMBER(19) not null,
  goods_title VARCHAR2(400),
  parent_id   NUMBER(19)
)
create table TB_ORGANIZATION
(
  id        NUMBER(19) not null,
  org_title VARCHAR2(400),
  parent_id NUMBER(19)
)
create table TB_WAREHOUSE
(
  id              NUMBER(19) not null,
  organization_id NUMBER(19),
  goods_id        NUMBER(19),
  doc_date        NUMBER(19),
  inventory       NUMBER(19)
)

insert into TB_GOODS (id, goods_title, parent_id)
values (1, 'Digital', 10);
insert into TB_GOODS (id, goods_title, parent_id)
values (2, 'Household', 10);
insert into TB_GOODS (id, goods_title, parent_id)
values (3, 'Cell Phone', 1);
insert into TB_GOODS (id, goods_title, parent_id)
values (4, 'TV', 1);
insert into TB_GOODS (id, goods_title, parent_id)
values (5, 'PS4 Console', 1);
insert into TB_GOODS (id, goods_title, parent_id)
values (6, 'Laptop', 1);
insert into TB_GOODS (id, goods_title, parent_id)
values (7, 'Fan', 2);
insert into TB_GOODS (id, goods_title, parent_id)
values (8, 'Key', 2);
insert into TB_GOODS (id, goods_title, parent_id)
values (9, 'Iron', 2);
insert into TB_GOODS (id, goods_title, parent_id)
values (10, 'Goods', null);
commit;

insert into TB_ORGANIZATION (id, org_title, parent_id)
values (1, 'A', null);
insert into TB_ORGANIZATION (id, org_title, parent_id)
values (2, 'B', 1);
insert into TB_ORGANIZATION (id, org_title, parent_id)
values (3, 'C', 1);
insert into TB_ORGANIZATION (id, org_title, parent_id)
values (4, 'D', 1);
insert into TB_ORGANIZATION (id, org_title, parent_id)
values (5, 'E', 2);
insert into TB_ORGANIZATION (id, org_title, parent_id)
values (6, 'F', 5);
insert into TB_ORGANIZATION (id, org_title, parent_id)
values (7, 'G', 6);
insert into TB_ORGANIZATION (id, org_title, parent_id)
values (8, 'H', 1);
commit;
insert into TB_WAREHOUSE (id, organization_id, goods_id, doc_date, inventory)
values (1, 2, 6, 20191202, -30);
insert into TB_WAREHOUSE (id, organization_id, goods_id, doc_date, inventory)
values (2, 2, 6, 20191202, 150);
insert into TB_WAREHOUSE (id, organization_id, goods_id, doc_date, inventory)
values (3, 2, 6, 20191206, -20);
insert into TB_WAREHOUSE (id, organization_id, goods_id, doc_date, inventory)
values (4, 2, 6, 20191206, 400);
insert into TB_WAREHOUSE (id, organization_id, goods_id, doc_date, inventory)
values (5, 1, 6, 20200105, 200);
insert into TB_WAREHOUSE (id, organization_id, goods_id, doc_date, inventory)
values (6, 1, 6, 20200102, -350);
commit;

Я могу отобразить общий ввод и вывод инвентаризации для каждого ORG_ID, GOODS_ID и DATE с помощью функции суммирования.

ORG_ID  GOODS_ID  DATE          INVENTORY
    2   6         2019-12-02    120
    2   6         2019-12-06    380
    1   6         2020-01-02    -350
    1   6         2020-01-05    200

Теперь в базе некоторых правил компании я должен отображать общий запас за каждый день, даже если для этого дня нет записей, как в следующей таблице

ORG_ID  GOODS_ID  DATE          INVENTORY
    2   6         2019-12-01    0
    2   6         2019-12-02    120
    2   6         2019-12-03    120
    2   6         2019-12-04    120
    2   6         2019-12-05    120
    2   6         2019-12-06    500
    2   6         2019-12-07    500
    2   6         2019-12-08    500
    2   6         2019-12-09    500
    2   6         2019-12-10    500
    2   6         2019-12-11    500
    2   6         2019-12-12    500
    2   6         2019-12-13    500
    2   6         2019-12-14    500
    2   6         2019-12-15    500
    2   6         2019-12-16    500
    2   6         2019-12-17    500
    2   6         2019-12-18    500
    2   6         2019-12-19    500
    2   6         2019-12-20    500
    2   6         2019-12-21    500
    2   6         2019-12-22    500
    2   6         2019-12-23    500
    2   6         2019-12-24    500
    2   6         2019-12-25    500
    2   6         2019-12-26    500
    2   6         2019-12-27    500
    2   6         2019-12-28    500
    2   6         2019-12-29    500
    2   6         2019-12-30    500
    1   6         2020-01-01    500
    1   6         2020-01-02    150
    1   6         2020-01-03    150
    1   6         2020-01-04    150
    1   6         2020-01-05    350
    1   6         2020-01-06    350
    1   6         2020-01-07    350
    1   6         2020-01-08    350
    1   6         2020-01-09    350
    1   6         2020-01-10    350
    1   6         2020-01-11    350
    1   6         2020-01-12    350
    1   6         2020-01-13    350
    1   6         2020-01-14    350
    1   6         2020-01-15    350
    1   6         2020-01-16    350
    1   6         2020-01-17    350
    1   6         2020-01-18    350
    1   6         2020-01-19    350
    1   6         2020-01-20    350
    1   6         2020-01-21    350
    1   6         2020-01-22    350
    1   6         2020-01-23    350
    1   6         2020-01-24    350
    1   6         2020-01-25    350
    1   6         2020-01-26    350
    1   6         2020-01-27    350
    1   6         2020-01-28    350
    1   6         2020-01-29    350
    1   6         2020-01-30    350

Теперь в финале я хочу отобразить среднее значение по месяцам в каждом ORGANIZATION_ID и GOODS_ID для каждого месяца в следующей таблице:

ORG_ID  GOODS_ID  DATE          INVENTORY Average
    1   6         2019-12       432.66
    2   6         2020-01       335 

Я думаю, что производительность - это очень важный факт для расчета моего склада с миллионами записей.

Спасибо за ваше руководство

Ответы [ 2 ]

1 голос
/ 07 мая 2019

Выполняет ли запрос агрегации то, что вы хотите?

select org_id, goods_id, trunc(date, 'Mon'), avg(inventory)
from t
group by org_id, goods_id, trunc(date, 'Mon');
0 голосов
/ 09 мая 2019

Я делаю это с помощью оператора SQL ниже, и моя проблема была решена.

WITH date_inventory_range AS
 (SELECT TRUNC(MIN(date_inventory), 'MONTH') AS first_date_inventory,
         ADD_MONTHS(TRUNC(MAX(date_inventory), 'MONTH'), 1) - 1 AS last_date_inventory

    FROM (SELECT W.ORGANIZATION_ID ORG_ID,
                 W.GOODS_ID,
                 W.DOC_DATE date_inventory,
                 SUM(W.INVENTORY) amount
            FROM TB_WAREHOUSE W
           GROUP BY W.ORGANIZATION_ID, W.GOODS_ID, W.DOC_DATE
           ORDER BY 3)),
all_dates AS
 (SELECT first_date_inventory + LEVEL - 1 AS date_inventory
    FROM date_inventory_range
  CONNECT BY LEVEL <= 1 + last_date_inventory - first_date_inventory),
dense_data AS
 (SELECT s.org_id,
         s.goods_id
         --  ,         d.date_inventory  -- For debugging only
        ,
         TRUNC(d.date_inventory, 'MONTH') AS mnth,
         NVL(SUM(s.amount) OVER(PARTITION BY s.org_id,
                  s.goods_id ORDER BY d.date_inventory),
             0) AS total_amount
    FROM all_dates d
    LEFT OUTER JOIN (SELECT W.ORGANIZATION_ID ORG_ID,
                           W.GOODS_ID,
                           W.DOC_DATE date_inventory,
                           SUM(W.INVENTORY) amount
                      FROM TB_WAREHOUSE W
                     GROUP BY W.ORGANIZATION_ID, W.GOODS_ID, W.DOC_DATE
                     ORDER BY 3) s PARTITION BY(s.org_id, s.goods_id)
      ON s.date_inventory = d.date_inventory)
SELECT org_id,
       goods_id,
       TO_CHAR(mnth, 'YYYY-MM') AS month,
       AVG(total_amount) AS month_avg
  FROM dense_data
 GROUP BY org_id, goods_id, mnth
 ORDER BY org_id, goods_id, mnth;
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...