Ниже для BigQuery Standard SQL
Идея состоит в том, чтобы сначала собрать все
- местоположения продукта (источник и место назначения)
- все группы продуктов
- и, наконец, все часы / дни для создания отчета за
Затем CROSS JOIN
все три выше и LEFT JOIN
с часами, днем, местоположением и группой товаров основных данных при расчете суммы на основекакое местоположение представляет - источник или место назначения.
Далее все суммы сгруппированы в один и тот же час / день и, очевидно, местоположение и Product_Group
И, наконец, аналитическая функция применяется для расчета совокупных сумм
Окончательный код с выборочными данными приведен ниже
#standardSQL
WITH `project.dataset.table` AS (
SELECT DATETIME '2019-02-01 08:01:00' Transaction_Datetime, 'Person1' Source, 'Shelf1' Destination, 1234 Product_ID, 1 Product_Group UNION ALL
SELECT '2019-02-01 10:01:00', 'Shelf1', 'Person1', 1234, 1 UNION ALL
SELECT '2019-02-01 08:03:00', 'Person2', 'Shelf1', 5678, 1
), hours AS (
SELECT EXTRACT(HOUR FROM hour) hour, DATE(hour) day
FROM (
SELECT
MIN(TIMESTAMP(Transaction_Datetime)) min_ts,
MAX(TIMESTAMP(Transaction_Datetime)) max_ts
FROM `project.dataset.table`
), UNNEST(GENERATE_TIMESTAMP_ARRAY(
TIMESTAMP_TRUNC(min_ts, HOUR),
TIMESTAMP_TRUNC(max_ts, HOUR),
INTERVAL 1 HOUR)) hour
), locations AS (
SELECT Source AS location FROM `project.dataset.table`
UNION DISTINCT
SELECT Destination FROM `project.dataset.table`
), product_groups AS (
SELECT DISTINCT Product_Group FROM `project.dataset.table`
), temp AS (
SELECT
EXTRACT(HOUR FROM Transaction_Datetime) hour,
DATE(Transaction_Datetime) day,
Source, Destination, Product_ID, Product_Group
FROM `project.dataset.table`
)
SELECT hour, day, location, product_group,
SUM(delta) OVER(PARTITION BY location, product_group ORDER BY hour, day) amount
FROM (
SELECT
hours.hour, hours.day, location, product_groups.product_group,
SUM(CASE location
WHEN Source THEN -1
WHEN Destination THEN 1
ELSE 0
END) delta
FROM locations, hours, product_groups
LEFT JOIN temp t
ON t.hour = hours.hour
AND t.day = hours.day
AND t.product_group = product_groups.product_group
AND location IN (Source, Destination)
GROUP BY hours.hour, hours.day, location, Product_Group
)
WHERE LOWER(location) LIKE 'shelf%'
-- ORDER BY hour, day, location
с результатом
Row hour day location product_group amount
1 8 2019-02-01 Shelf1 1 2
2 9 2019-02-01 Shelf1 1 2
3 10 2019-02-01 Shelf1 1 1
Примечание: из вашего вопроса не совсем понятно, как отличить Shelf
от Person
- поэтому используется LOWER(location) LIKE 'shelf%'
.Вы можете настроить это, чтобы использовать любую логику, которая у вас есть для этого
Если вы удалите эту строку - вы получите количество не только для полок, но и баланс продукта в «руке» каждого человека
.протестируйте с вашей таблицей - запустите ниже - не забудьте заменить `project.dataset.table` вашей полной ссылкой на таблицу
#standardSQL
WITH hours AS (
SELECT EXTRACT(HOUR FROM hour) hour, DATE(hour) day
FROM (
SELECT
MIN(TIMESTAMP(Transaction_Datetime)) min_ts,
MAX(TIMESTAMP(Transaction_Datetime)) max_ts
FROM `project.dataset.table`
), UNNEST(GENERATE_TIMESTAMP_ARRAY(
TIMESTAMP_TRUNC(min_ts, HOUR),
TIMESTAMP_TRUNC(max_ts, HOUR),
INTERVAL 1 HOUR)) hour
), locations AS (
SELECT Source AS location FROM `project.dataset.table`
UNION DISTINCT
SELECT Destination FROM `project.dataset.table`
), product_groups AS (
SELECT DISTINCT Product_Group FROM `project.dataset.table`
), temp AS (
SELECT
EXTRACT(HOUR FROM Transaction_Datetime) hour,
DATE(Transaction_Datetime) day,
Source, Destination, Product_ID, Product_Group
FROM `project.dataset.table`
)
SELECT hour, day, location, product_group,
SUM(delta) OVER(PARTITION BY location, product_group ORDER BY hour, day) amount
FROM (
SELECT
hours.hour, hours.day, location, product_groups.product_group,
SUM(CASE location
WHEN Source THEN -1
WHEN Destination THEN 1
ELSE 0
END) delta
FROM locations, hours, product_groups
LEFT JOIN temp t
ON t.hour = hours.hour
AND t.day = hours.day
AND t.product_group = product_groups.product_group
AND location IN (Source, Destination)
GROUP BY hours.hour, hours.day, location, Product_Group
)
WHERE LOWER(location) LIKE 'shelf%'
-- ORDER BY hour, day, location