perf(selfop): skip unavailable dashboard aggregates
This commit is contained in:
+8
-5
@@ -17,7 +17,9 @@ public final class AnalyticsInventorySql {
|
||||
private static String defectiveQuantity(){return "CASE WHEN MIN(CASE WHEN product_quality NOT IN (0,1) THEN 0 WHEN product_quality=1 THEN CASE WHEN "+valid("physical_quantity")+" THEN 1 ELSE 0 END ELSE 1 END)=1 "
|
||||
+"THEN SUM(CASE WHEN product_quality=1 THEN physical_quantity ELSE 0 END) END";}
|
||||
static String cte(AnalyticsSqlRequest p){return cte(p,false);}
|
||||
private static String cte(AnalyticsSqlRequest p,boolean stockFirst){
|
||||
static String dashboardCte(AnalyticsSqlRequest p){return cte(p,false,true);}
|
||||
private static String cte(AnalyticsSqlRequest p,boolean stockFirst){return cte(p,stockFirst,false);}
|
||||
private static String cte(AnalyticsSqlRequest p,boolean stockFirst,boolean dashboard){
|
||||
return "WITH candidates AS ("+keys(p)+"), profiles AS (SELECT c.customer_code,c.sku_code,COALESCE(i.product_name,s.product_name) product_name,"
|
||||
+"CASE WHEN i.quantity_unit='PCS' THEN 1 ELSE 0 END stock_unit_valid,"
|
||||
+"CASE WHEN s.sku_code IS NULL OR s.quantity_unit='PCS' THEN 1 ELSE 0 END sales_unit_valid,"
|
||||
@@ -29,9 +31,10 @@ public final class AnalyticsInventorySql {
|
||||
+" stock AS (SELECT customer_code,sku_code,"+quantity("physical_quantity")+" physical_quantity,"+quantity("frozen_quantity")+" frozen_quantity,"
|
||||
+quantity("transit_quantity")+" transit_quantity,MAX(CASE WHEN product_quality=0 AND "+valid("available_quantity")+" THEN available_quantity END) available_quantity,"
|
||||
+defectiveQuantity()+" defective_physical_quantity,MAX(observed_at_utc) observed_at_utc "
|
||||
+"FROM ll_selfop_inventory_snapshot WHERE snapshot_run_id=#{p.inventoryRun} AND"+scope(p)+" GROUP BY customer_code,sku_code),"
|
||||
+"FROM ll_selfop_inventory_snapshot WHERE "+(dashboard&&!p.stockFresh()?"1=0 /* dashboard unused stock */ AND ":"")
|
||||
+"snapshot_run_id=#{p.inventoryRun} AND"+scope(p)+" GROUP BY customer_code,sku_code),"
|
||||
+(stockFirst?stockPageKeys():"")
|
||||
+salesCte(p,stockFirst)
|
||||
+salesCte(p,stockFirst,dashboard&&!p.complete30())
|
||||
+" values_by_sku AS (SELECT c.customer_code,c.sku_code,c.product_name,c.unit_valid,"
|
||||
+"CASE WHEN c.sales_evidence IS NULL THEN c.stock_evidence WHEN c.stock_evidence IS NULL THEN c.sales_evidence ELSE LEAST(c.sales_evidence,c.stock_evidence) END evidence_at_utc,"
|
||||
+stockValue("physical_quantity")+","+stockValue("available_quantity")+","+stockValue("frozen_quantity")+","+stockValue("transit_quantity")+","+stockValue("defective_physical_quantity")+",st.observed_at_utc,"
|
||||
@@ -47,12 +50,12 @@ public final class AnalyticsInventorySql {
|
||||
+"WHEN physical_quantity>0 AND available_quantity>0 AND outbound_quantity30d IS NOT NULL THEN CASE WHEN outbound_quantity30d>0 AND available_quantity*30>outbound_quantity30d*#{o.coverageDaysThreshold} THEN 1 ELSE 0 END END above_threshold "
|
||||
+"FROM qualified q), result AS (SELECT c.*,CASE WHEN physical_quantity IS NULL OR available_quantity IS NULL OR outbound_quantity30d IS NULL THEN 1 ELSE 0 END unassessable FROM calculated c) ";
|
||||
}
|
||||
private static String salesCte(AnalyticsSqlRequest p,boolean stockFirst){String d=stockFirst?"d.":"";
|
||||
private static String salesCte(AnalyticsSqlRequest p,boolean stockFirst,boolean unused){String d=stockFirst?"d.":"";
|
||||
return " sales AS (SELECT "+(stockFirst?"/*+ JOIN_ORDER(k,d) INDEX(d idx_selfop_daily_sku_cover) */ ":"")
|
||||
+d+"customer_code,"+d+"sku_code,SUM("+d+"outbound_quantity) observed_quantity,SUM("+d+"outbound_order_count) order_count,"
|
||||
+"MIN(CASE WHEN "+d+"quantity_unit='PCS' AND "+d+"outbound_quantity>=0 THEN 1 ELSE 0 END) unit_valid FROM ll_selfop_sku_daily_sales "
|
||||
+(stockFirst?"d JOIN stock_paged k ON k.customer_code=d.customer_code AND k.sku_code=d.sku_code ":"")
|
||||
+"WHERE "+d+"sales_run_id=#{p.salesRun} AND"+scope(p,d)+" AND "+d+"business_date>=#{p.from} AND "+d+"business_date<#{p.until} GROUP BY "+d+"customer_code,"+d+"sku_code),";
|
||||
+"WHERE "+(unused?"1=0 /* dashboard unused sales */ AND ":"")+d+"sales_run_id=#{p.salesRun} AND"+scope(p,d)+" AND "+d+"business_date>=#{p.from} AND "+d+"business_date<#{p.until} GROUP BY "+d+"customer_code,"+d+"sku_code),";
|
||||
}
|
||||
private static String stockAmount(String field){return "CASE WHEN c.stock_unit_valid=1 AND #{p.stockFresh}=1 THEN st."+field+" END";}
|
||||
private static String stockValue(String field){return stockAmount(field)+" "+field;}
|
||||
|
||||
+6
-1
@@ -7,7 +7,12 @@ import java.util.Map;
|
||||
public final class DashboardReadSql {
|
||||
private DashboardReadSql(){}
|
||||
public static String report(Map<String,Object> args){
|
||||
var p=(AnalyticsSqlRequest)args.get("p");StringBuilder sql=new StringBuilder(AnalyticsInventorySql.cte(p));
|
||||
var p=(AnalyticsSqlRequest)args.get("p");
|
||||
// Only dashboard outputs are considered here. Without complete30 all sales-dependent
|
||||
// rankings are empty; observed sales still come from the independent daily query.
|
||||
// Stale stock quantities are already masked to NULL. Keep both profile versions so
|
||||
// candidate identities, observation evidence and unknown reasons remain unchanged.
|
||||
StringBuilder sql=new StringBuilder(AnalyticsInventorySql.dashboardCte(p));
|
||||
// SKU identity is unique already; DISTINCT is a MySQL merge barrier so the four consumers
|
||||
// share one calculation rather than expanding profile/stock/sales joins for each ranking.
|
||||
sql.append(", dashboard_result AS (SELECT DISTINCT * FROM result)");
|
||||
|
||||
Reference in New Issue
Block a user