ecc/InventoryKeyMetrics.sql (385 lines of code) (raw):
--This query groups the data by Client, MaterialNumber, Plant, CalYear, CalMonth, Target Currency
--## CORTEX-CUSTOMER: Please consider materializing this view for better performance
--and cost as this is pretty heavy in run-time calculation
WITH
CurrencyConversion AS (
SELECT
Client_MANDT, FromCurrency_FCURR, ToCurrency_TCURR, ConvDate, ExchangeRate_UKURS
FROM
`{{ project_id_tgt }}.{{ dataset_reporting_tgt }}.CurrencyConversion`
WHERE
ToCurrency_TCURR IN UNNEST({{ sap_currencies }})
--##CORTEX-CUSTOMER Modify the exchange rate type based on your requirement
AND ExchangeRateType_KURST = 'M'
),
ValueAndCost AS (
SELECT DISTINCT
StockMonthlySnapshots.Client_MANDT,
StockMonthlySnapshots.MaterialNumber_MATNR,
StockMonthlySnapshots.Plant_WERKS,
StockMonthlySnapshots.MonthEndDate,
StockMonthlySnapshots.FiscalYear,
StockMonthlySnapshots.FiscalPeriod,
COALESCE(
MaterialLedger.ValueOfTotalValuatedStock_SALK3,
LAST_VALUE(MaterialLedger.ValueOfTotalValuatedStock_SALK3 IGNORE NULLS)
OVER ( -- noqa: disable=L003
PARTITION BY
StockMonthlySnapshots.MaterialNumber_MATNR, StockMonthlySnapshots.Plant_WERKS
ORDER BY
StockMonthlySnapshots.MonthEndDate
ROWS BETWEEN UNBOUNDED PRECEDING AND CURRENT ROW
)) AS ValueOfTotalValuatedStock_SALK3,
COALESCE(
MaterialLedger.StandardCost_STPRS,
LAST_VALUE(MaterialLedger.StandardCost_STPRS IGNORE NULLS)
OVER (
PARTITION BY
StockMonthlySnapshots.MaterialNumber_MATNR, StockMonthlySnapshots.Plant_WERKS
ORDER BY
StockMonthlySnapshots.MonthEndDate
ROWS BETWEEN UNBOUNDED PRECEDING AND CURRENT ROW
)) AS StandardCost_STPRS,
COALESCE(
MaterialLedger.MovingAveragePrice,
LAST_VALUE(MaterialLedger.MovingAveragePrice IGNORE NULLS)
OVER (
PARTITION BY
StockMonthlySnapshots.MaterialNumber_MATNR, StockMonthlySnapshots.Plant_WERKS
ORDER BY
StockMonthlySnapshots.MonthEndDate
ROWS BETWEEN UNBOUNDED PRECEDING AND CURRENT ROW
)) AS MovingAveragePrice_VERPR
FROM --noqa: enable=all
`{{ project_id_tgt }}.{{ dataset_reporting_tgt }}.StockMonthlySnapshots` AS StockMonthlySnapshots
LEFT JOIN
`{{ project_id_tgt }}.{{ dataset_reporting_tgt }}.MaterialLedger` AS MaterialLedger
ON
StockMonthlySnapshots.Client_MANDT = MaterialLedger.Client_MANDT
AND StockMonthlySnapshots.MaterialNumber_MATNR = MaterialLedger.MaterialNumber_MATNR
AND StockMonthlySnapshots.Plant_WERKS = MaterialLedger.ValuationArea_BWKEY
AND StockMonthlySnapshots.FiscalYear = MaterialLedger.FiscalYear
AND RIGHT(StockMonthlySnapshots.FiscalPeriod, 2) = MaterialLedger.PostingPeriod
AND MaterialLedger.ValuationType_BWTAR = ''
),
-- TODO: Consider materializing this CTE to avoid multiple evaluations.
CurrentStock AS (
SELECT
StockMonthlySnapshots.Client_MANDT,
StockMonthlySnapshots.MaterialNumber_MATNR,
StockMonthlySnapshots.Plant_WERKS,
StockMonthlySnapshots.MaterialType_MTART,
SlowMovingThreshold.ThresholdValue,
StockMonthlySnapshots.DescriptionOfMaterialType_MTBEZ,
StockMonthlySnapshots.MaterialText_MAKTX,
StockMonthlySnapshots.MaterialGroup_MATKL,
StockMonthlySnapshots.MaterialGroupName_WGBEZ,
StockMonthlySnapshots.Plant_Name2_NAME2,
StockMonthlySnapshots.CompanyCode_BUKRS,
StockMonthlySnapshots.CompanyText_BUTXT,
StockMonthlySnapshots.CountryKey_LAND1,
StockMonthlySnapshots.LanguageKey_SPRAS,
StockMonthlySnapshots.BaseUnitOfMeasure_MEINS,
StockMonthlySnapshots.CurrencyKey_WAERS,
StockMonthlySnapshots.FiscalYear,
StockMonthlySnapshots.FiscalPeriod,
StockMonthlySnapshots.CalYear,
StockMonthlySnapshots.CalMonth,
IF(
StockMonthlySnapshots.MonthEndDate = LAST_DAY(CURRENT_DATE),
CURRENT_DATE,
StockMonthlySnapshots.MonthEndDate
) AS MonthEndDate,
StockMonthlySnapshots.MonthEndDate
BETWEEN -- noqa: disable=L003
LAST_DAY(DATE_SUB(CURRENT_DATE, INTERVAL 12 MONTH))
AND
LAST_DAY(DATE_SUB(CURRENT_DATE, INTERVAL 1 MONTH))
AS IsPast12MonthsExcludingCurrent,
StockMonthlySnapshots.MonthEndDate
BETWEEN
LAST_DAY(DATE_SUB(CURRENT_DATE, INTERVAL 12 MONTH))
AND
LAST_DAY(CURRENT_DATE)
AS IsPast12MonthsIncludingCurrent,
ValueAndCost.ValueOfTotalValuatedStock_SALK3, --noqa: enable=all
ValueAndCost.StandardCost_STPRS,
ValueAndCost.MovingAveragePrice_VERPR,
SUM(StockMonthlySnapshots.QuantityMonthlyCumulative) AS QuantityMonthlyCumulative,
SUM(StockMonthlySnapshots.AmountMonthlyCumulative) AS AmountMonthlyCumulative,
SUM(StockMonthlySnapshots.StockOnHand) AS StockOnHand,
SUM(StockMonthlySnapshots.StockOnHandValue) AS StockOnHandValue,
SUM(StockMonthlySnapshots.QuantityIssuedToDelivery) AS QuantityIssuedToDelivery,
SUM(StockMonthlySnapshots.TotalConsumptionQuantity) AS TotalConsumptionQuantity
FROM
-- TODO: Evaluate if all columns in StockMonthlySnapshots can be moved into ValueAndCost
-- so we don't need to query the source table twice.
`{{ project_id_tgt }}.{{ dataset_reporting_tgt }}.StockMonthlySnapshots` AS StockMonthlySnapshots
LEFT JOIN
ValueAndCost
ON
StockMonthlySnapshots.Client_MANDT = ValueAndCost.Client_MANDT
AND StockMonthlySnapshots.MaterialNumber_MATNR = ValueAndCost.MaterialNumber_MATNR
AND StockMonthlySnapshots.Plant_WERKS = ValueAndCost.Plant_WERKS
AND StockMonthlySnapshots.MonthEndDate = ValueAndCost.MonthEndDate
AND StockMonthlySnapshots.FiscalPeriod = ValueAndCost.FiscalPeriod
AND StockMonthlySnapshots.FiscalYear = ValueAndCost.FiscalYear
LEFT JOIN
`{{ project_id_tgt }}.{{ dataset_reporting_tgt }}.SlowMovingThreshold` AS SlowMovingThreshold
ON
StockMonthlySnapshots.Client_MANDT = SlowMovingThreshold.Client_MANDT
AND StockMonthlySnapshots.MaterialType_MTART = SlowMovingThreshold.MaterialType_MTART
GROUP BY
StockMonthlySnapshots.Client_MANDT,
StockMonthlySnapshots.MaterialNumber_MATNR,
StockMonthlySnapshots.Plant_WERKS,
StockMonthlySnapshots.MaterialType_MTART,
SlowMovingThreshold.ThresholdValue,
StockMonthlySnapshots.DescriptionOfMaterialType_MTBEZ,
StockMonthlySnapshots.MaterialText_MAKTX,
StockMonthlySnapshots.MaterialGroup_MATKL,
StockMonthlySnapshots.MaterialGroupName_WGBEZ,
StockMonthlySnapshots.Plant_Name2_NAME2,
StockMonthlySnapshots.CompanyCode_BUKRS,
StockMonthlySnapshots.CompanyText_BUTXT,
StockMonthlySnapshots.CountryKey_LAND1,
StockMonthlySnapshots.LanguageKey_SPRAS,
ValueAndCost.ValueOfTotalValuatedStock_SALK3,
ValueAndCost.StandardCost_STPRS,
ValueAndCost.MovingAveragePrice_VERPR,
StockMonthlySnapshots.BaseUnitOfMeasure_MEINS,
StockMonthlySnapshots.CurrencyKey_WAERS,
StockMonthlySnapshots.FiscalYear,
StockMonthlySnapshots.FiscalPeriod,
StockMonthlySnapshots.CalYear,
StockMonthlySnapshots.CalMonth,
StockMonthlySnapshots.MonthEndDate
),
CalculatedMetrics AS (
SELECT DISTINCT
CurrentStock.Client_MANDT,
CurrentStock.MaterialNumber_MATNR,
CurrentStock.Plant_WERKS,
CurrentStock.LanguageKey_SPRAS,
CurrentStock.MonthEndDate,
CurrentStock.FiscalPeriod,
CurrentStock.FiscalYear,
-- TotalConsumptionQuantity for past 12 months excluding current month
IF(
IsPast12MonthsExcludingCurrent,
SUM(CurrentStock.TotalConsumptionQuantity)
OVER ( -- noqa: disable=L003
PARTITION BY
CurrentStock.Client_MANDT, CurrentStock.MaterialNumber_MATNR,
CurrentStock.Plant_WERKS, CurrentStock.LanguageKey_SPRAS,
IsPast12MonthsExcludingCurrent),
0) AS TotalConsumptionQuantityForPastYear,
-- TotalConsumptionQuantity For Past 12 Months To Current Date
IF(
IsPast12MonthsIncludingCurrent,
SUM(CurrentStock.TotalConsumptionQuantity)
OVER (
PARTITION BY
CurrentStock.Client_MANDT, CurrentStock.MaterialNumber_MATNR,
CurrentStock.Plant_WERKS, CurrentStock.LanguageKey_SPRAS,
IsPast12MonthsIncludingCurrent),
0) AS TotalConsumptionQuantityForPastYearTillToday,
-- Demand Per Day For Past 12 Months To Current Date
IF(
IsPast12MonthsIncludingCurrent,
SUM(TotalConsumptionQuantity / (365 + EXTRACT(DAY FROM CURRENT_DATE)))
OVER (
PARTITION BY
CurrentStock.Client_MANDT, CurrentStock.MaterialNumber_MATNR,
CurrentStock.Plant_WERKS, CurrentStock.LanguageKey_SPRAS,
IsPast12MonthsIncludingCurrent),
0) AS DemandPerDayForPastYearTillToday,
-- Inventory For Each Month
SUM(CurrentStock.ValueOfTotalValuatedStock_SALK3)
OVER (
PARTITION BY
CurrentStock.Client_MANDT, CurrentStock.MaterialNumber_MATNR,
CurrentStock.Plant_WERKS, CurrentStock.LanguageKey_SPRAS
ORDER BY
CurrentStock.CalYear, CurrentStock.CalMonth
ROWS BETWEEN 2 PRECEDING AND 1 PRECEDING
) AS InventoryByMonth,
-- Avg Inventory For Each Month
SUM(CurrentStock.ValueOfTotalValuatedStock_SALK3 / 2)
OVER (
PARTITION BY
CurrentStock.Client_MANDT, CurrentStock.MaterialNumber_MATNR,
CurrentStock.Plant_WERKS, CurrentStock.LanguageKey_SPRAS
ORDER BY
CurrentStock.CalYear, CurrentStock.CalMonth
ROWS BETWEEN 2 PRECEDING AND 1 PRECEDING
) AS AvgInventoryByMonth
FROM -- noqa: enable=all
CurrentStock
),
Inventory AS (
SELECT
CurrentStock.Client_MANDT,
CurrentStock.MaterialNumber_MATNR,
CurrentStock.Plant_WERKS,
CurrentStock.MaterialType_MTART,
CurrentStock.ThresholdValue,
CurrentStock.DescriptionOfMaterialType_MTBEZ,
CurrentStock.MaterialText_MAKTX,
CurrentStock.MaterialGroup_MATKL,
CurrentStock.MaterialGroupName_WGBEZ,
CurrentStock.Plant_Name2_NAME2,
CurrentStock.CompanyCode_BUKRS,
CurrentStock.CompanyText_BUTXT,
CurrentStock.CountryKey_LAND1,
CurrentStock.LanguageKey_SPRAS,
CurrentStock.ValueOfTotalValuatedStock_SALK3,
CurrentStock.StandardCost_STPRS,
CurrentStock.MovingAveragePrice_VERPR,
CurrentStock.BaseUnitOfMeasure_MEINS,
CurrentStock.CurrencyKey_WAERS,
CurrentStock.FiscalYear,
CurrentStock.FiscalPeriod,
CurrentStock.CalYear,
CurrentStock.CalMonth,
CurrentStock.MonthEndDate,
CurrentStock.QuantityMonthlyCumulative,
CurrentStock.AmountMonthlyCumulative,
CurrentStock.StockOnHand,
CurrentStock.StockOnHandValue,
CurrentStock.QuantityIssuedToDelivery,
CurrentStock.TotalConsumptionQuantity,
CurrentStock.QuantityIssuedToDelivery * CurrentStock.StandardCost_STPRS AS CostOfGoodsSoldByMonth,
CalculatedMetrics.TotalConsumptionQuantityForPastYear,
CalculatedMetrics.TotalConsumptionQuantityForPastYearTillToday,
CalculatedMetrics.DemandPerDayForPastYearTillToday,
CalculatedMetrics.InventoryByMonth,
CalculatedMetrics.AvgInventoryByMonth,
-- Inventory Value
CASE
WHEN CurrentStock.MaterialType_MTART IN ('FERT', 'HALB')
THEN CurrentStock.QuantityMonthlyCumulative * CurrentStock.StandardCost_STPRS
WHEN CurrentStock.MaterialType_MTART IN ('ROH', 'HIBE')
THEN CurrentStock.QuantityMonthlyCumulative * CurrentStock.MovingAveragePrice_VERPR
ELSE 0
END AS InventoryValue
FROM
CurrentStock
LEFT JOIN
CalculatedMetrics
ON
CurrentStock.Client_MANDT = CalculatedMetrics.Client_MANDT
AND CurrentStock.MaterialNumber_MATNR = CalculatedMetrics.MaterialNumber_MATNR
AND CurrentStock.Plant_WERKS = CalculatedMetrics.Plant_WERKS
AND CurrentStock.LanguageKey_SPRAS = CalculatedMetrics.LanguageKey_SPRAS
AND CurrentStock.MonthEndDate = CalculatedMetrics.MonthEndDate
AND CurrentStock.FiscalPeriod = CalculatedMetrics.FiscalPeriod
AND CurrentStock.FiscalYear = CalculatedMetrics.FiscalYear
)
SELECT
Inventory.Client_MANDT,
Inventory.MaterialNumber_MATNR,
Inventory.Plant_WERKS,
Inventory.MaterialType_MTART,
Inventory.DescriptionOfMaterialType_MTBEZ,
Inventory.MaterialText_MAKTX,
Inventory.MaterialGroup_MATKL,
Inventory.MaterialGroupName_WGBEZ,
Inventory.Plant_Name2_NAME2,
Inventory.CompanyCode_BUKRS,
Inventory.CompanyText_BUTXT,
Inventory.CountryKey_LAND1,
Inventory.LanguageKey_SPRAS,
Inventory.FiscalYear,
Inventory.FiscalPeriod,
Inventory.CalYear,
Inventory.CalMonth,
Inventory.MonthEndDate,
Inventory.QuantityMonthlyCumulative,
Inventory.BaseUnitOfMeasure_MEINS,
Inventory.AmountMonthlyCumulative,
Inventory.CurrencyKey_WAERS,
Inventory.StockOnHand,
Inventory.StockOnHandValue,
Inventory.QuantityIssuedToDelivery,
Inventory.TotalConsumptionQuantity,
Inventory.ValueOfTotalValuatedStock_SALK3,
Inventory.StandardCost_STPRS,
Inventory.MovingAveragePrice_VERPR,
Inventory.TotalConsumptionQuantityForPastYear,
Inventory.TotalConsumptionQuantityForPastYearTillToday,
Inventory.DemandPerDayForPastYearTillToday,
Inventory.CostOfGoodsSoldByMonth,
Inventory.InventoryValue,
Inventory.ThresholdValue,
Inventory.InventoryByMonth,
Inventory.AvgInventoryByMonth,
-- The following columns are having amount/prices in target currency.
CurrencyConversion.ExchangeRate_UKURS,
CurrencyConversion.ToCurrency_TCURR AS TargetCurrency_TCURR,
Inventory.AmountMonthlyCumulative * CurrencyConversion.ExchangeRate_UKURS AS AmountMonthlyCumulativeInTargetCurrency,
Inventory.StockOnHandValue * CurrencyConversion.ExchangeRate_UKURS AS StockOnHandValueInTargetCurrency,
Inventory.StandardCost_STPRS * CurrencyConversion.ExchangeRate_UKURS AS StandardCostInTargetCurrency_STPRS,
Inventory.MovingAveragePrice_VERPR * CurrencyConversion.ExchangeRate_UKURS AS MovingAveragePriceInTargetCurrency_VERPR,
Inventory.CostOfGoodsSoldByMonth * CurrencyConversion.ExchangeRate_UKURS AS CostofGoodsSoldInTargetCurrency,
Inventory.InventoryValue * CurrencyConversion.ExchangeRate_UKURS AS InventoryValueInTargetCurrency,
Inventory.InventoryByMonth * CurrencyConversion.ExchangeRate_UKURS AS InventoryByMonthInTargetCurrency,
Inventory.AvgInventoryByMonth * CurrencyConversion.ExchangeRate_UKURS AS AvgInventoryByMonthInTargetCurrency,
Inventory.ValueOfTotalValuatedStock_SALK3 * CurrencyConversion.ExchangeRate_UKURS AS ValueOfTotalValuatedStockInTargetCurrency_SALK3,
-- Slow Moving Inventory In Target Currency
IF(
COALESCE(
IF(
Inventory.MonthEndDate = LAST_DAY(DATE_SUB(CURRENT_DATE, INTERVAL 1 MONTH)),
SAFE_DIVIDE((Inventory.TotalConsumptionQuantityForPastYear * 100), Inventory.StockOnHand),
0
),
0
) < Inventory.ThresholdValue,
IF(
Inventory.MonthEndDate = LAST_DAY(DATE_SUB(CURRENT_DATE, INTERVAL 1 MONTH)),
(Inventory.StockOnHandValue * CurrencyConversion.ExchangeRate_UKURS),
0
),
0
) AS SlowMovingInventoryAsOfPreviousMonthInTargetCurrency,
-- Days Of Supply
COALESCE(
IF(
Inventory.MonthEndDate = CURRENT_DATE,
SAFE_DIVIDE(Inventory.StockOnHand, Inventory.DemandPerDayForPastYearTillToday),
0
),
0
) AS DaysOfSupplyAsOfToday,
-- Slow Moving Indicator
IF(
COALESCE(
IF(
Inventory.MonthEndDate = LAST_DAY(DATE_SUB(CURRENT_DATE, INTERVAL 1 MONTH)),
SAFE_DIVIDE((Inventory.TotalConsumptionQuantityForPastYear * 100), Inventory.StockOnHand),
0
),
0
) < Inventory.ThresholdValue,
COALESCE(
IF(
Inventory.MonthEndDate = LAST_DAY(DATE_SUB(CURRENT_DATE, INTERVAL 1 MONTH)),
SAFE_DIVIDE((Inventory.TotalConsumptionQuantityForPastYear * 100), Inventory.StockOnHand),
0
),
0
),
0
) AS SlowMovingIndicatorAsOfPreviousMonth,
-- Slow Moving Inventory In Source Currency
IF(
COALESCE(
IF(
Inventory.MonthEndDate = LAST_DAY(DATE_SUB(CURRENT_DATE, INTERVAL 1 MONTH)),
SAFE_DIVIDE((Inventory.TotalConsumptionQuantityForPastYear * 100), Inventory.StockOnHand),
0
),
0
) < Inventory.ThresholdValue,
IF(
Inventory.MonthEndDate = LAST_DAY(DATE_SUB(CURRENT_DATE, INTERVAL 1 MONTH)),
Inventory.StockOnHandValue,
0
),
0
) AS SlowMovingInventoryAsOfPreviousMonthInSourceCurrency,
-- Inventory Turn
COALESCE(
SAFE_DIVIDE(Inventory.CostOfGoodsSoldByMonth, Inventory.AvgInventoryByMonth),
0
) AS InventoryTurnByMonth
FROM
Inventory
LEFT JOIN
CurrencyConversion
ON
Inventory.Client_MANDT = CurrencyConversion.Client_MANDT
AND Inventory.CurrencyKey_WAERS = CurrencyConversion.FromCurrency_FCURR
AND Inventory.MonthEndDate = CurrencyConversion.ConvDate