perf(lastleg): reduce inventory turnover query aggregation work

This commit is contained in:
2026-10-14 03:36:54 +08:00
parent 16d0b9c80f
commit 765b6e6208
3 changed files with 353 additions and 37 deletions
@@ -38,39 +38,38 @@ public final class InventoryTurnoverSql {
+"CAST(#{p.days["+i+"].coverage} AS SIGNED) coverage,CAST(#{p.days["+i+"].sampleRun,jdbcType=BIGINT} AS SIGNED) sample_run");
return String.join(" UNION ALL ",parts);
}
private static String sampleRuns(Input p) {
// The frozen context already resolved these versions. Bind them directly instead
// of repeatedly expanding the 30-day calendar as a membership subquery.
var runs=new ArrayList<String>();
for(int i=0;i<p.days().size();i++) if(p.days().get(i).sampleRun()!=null)
runs.add("#{p.days["+i+"].sampleRun,jdbcType=BIGINT}");
return runs.isEmpty()?"NULL":String.join(",",runs);
}
private static String salesDays() {
return "SELECT customer_code,sku_code,business_date,SUM(outbound_quantity) quantity,MIN(CASE WHEN quantity_unit='PCS' AND outbound_quantity>=0 THEN 1 ELSE 0 END) unit_valid FROM ll_selfop_sku_daily_sales WHERE "
+scope("")+" AND sales_run_id=#{p.salesRun} AND business_date>=CAST(#{p.from} AS DATE) AND business_date<CAST(#{p.until} AS DATE) GROUP BY customer_code,sku_code,business_date";
}
private static String cte(Input p) {
String stocks="SELECT snapshot_run_id,customer_code,sku_code,"+amount("physical_quantity")+" physical,"
+amount("frozen_quantity")+" frozen,MAX(CASE WHEN product_quality=0 AND "+valid("available_quantity")+" THEN available_quantity END) available,"
+"CASE WHEN MIN(CASE WHEN product_quality NOT IN (0,1) OR product_quality IS NULL THEN 0 WHEN product_quality=1 AND NOT ("+valid("physical_quantity")+") THEN 0 ELSE 1 END)=1 "
+"THEN SUM(CASE WHEN product_quality=1 THEN physical_quantity ELSE 0 END) END defective "
+"FROM ll_selfop_inventory_snapshot WHERE "+scope("")+" AND (snapshot_run_id=#{p.inventoryRun} OR snapshot_run_id IN (SELECT sample_run FROM calendar)) "
+"FROM ll_selfop_inventory_snapshot WHERE "+scope("")+" AND (snapshot_run_id=#{p.inventoryRun} OR snapshot_run_id IN ("+sampleRuns(p)+")) "
+"GROUP BY snapshot_run_id,customer_code,sku_code";
String profiles="SELECT * FROM ll_selfop_sku_profile WHERE "+scope("")+" AND (profile_run_id IN (#{p.salesRun},#{p.inventoryRun}) OR profile_run_id IN (SELECT sample_run FROM calendar))";
String profiles="SELECT * FROM ll_selfop_sku_profile WHERE "+scope("")+" AND (profile_run_id IN (#{p.salesRun},#{p.inventoryRun}) OR profile_run_id IN ("+sampleRuns(p)+"))";
StringBuilder sql=new StringBuilder("WITH calendar AS (").append(calendar(p)).append("), fixed_profiles AS (").append(profiles)
.append("), stocks AS (").append(stocks).append("), sales_days AS (SELECT customer_code,sku_code,business_date,SUM(outbound_quantity) quantity,MIN(CASE WHEN quantity_unit='PCS' AND outbound_quantity>=0 THEN 1 ELSE 0 END) unit_valid FROM ll_selfop_sku_daily_sales WHERE ")
.append(scope("")).append(" AND sales_run_id=#{p.salesRun} AND business_date>=CAST(#{p.from} AS DATE) AND business_date<CAST(#{p.until} AS DATE) GROUP BY customer_code,sku_code,business_date), candidates AS (")
.append("), stocks AS (").append(stocks).append("), sales_days AS (").append(salesDays()).append("), candidates AS (")
.append("SELECT customer_code,sku_code FROM fixed_profiles UNION SELECT customer_code,sku_code FROM stocks UNION SELECT customer_code,sku_code FROM sales_days), profiles AS (")
.append("SELECT c.customer_code,c.sku_code,COALESCE(MAX(CASE WHEN f.profile_run_id=#{p.inventoryRun} THEN f.product_name END),MAX(f.product_name)) product_name,")
.append("COALESCE(MAX(CASE WHEN f.profile_run_id=#{p.salesRun} THEN CASE WHEN f.quantity_unit='PCS' THEN 1 ELSE 0 END END),MAX(CASE WHEN f.profile_run_id=#{p.inventoryRun} THEN CASE WHEN f.quantity_unit='PCS' THEN 1 ELSE 0 END END),MIN(CASE WHEN f.quantity_unit='PCS' THEN 1 ELSE 0 END)) unit_valid,")
.append("MIN(CASE WHEN f.evidence_run_id IS NOT NULL AND f.evidence_type IN ('VALID_OUTBOUND','INVENTORY_OBSERVATION') THEN f.earliest_evidence_at_utc END) evidence ")
.append("FROM candidates c LEFT JOIN fixed_profiles f ON f.customer_code=c.customer_code AND f.sku_code=c.sku_code GROUP BY c.customer_code,c.sku_code), daily_values AS (")
.append("SELECT c.customer_code,c.sku_code,d.business_date,d.coverage,c.unit_valid,c.evidence,sd.quantity,sd.unit_valid sales_unit,")
.append("CASE WHEN ip.quantity_unit='PCS' THEN hs.physical END sample_physical ")
.append("FROM profiles c CROSS JOIN calendar d LEFT JOIN sales_days sd ON sd.customer_code=c.customer_code AND sd.sku_code=c.sku_code AND sd.business_date=d.business_date ")
.append("LEFT JOIN stocks hs ON hs.snapshot_run_id=d.sample_run AND hs.customer_code=c.customer_code AND hs.sku_code=c.sku_code ")
.append("LEFT JOIN fixed_profiles ip ON ip.profile_run_id=d.sample_run AND ip.customer_code=c.customer_code AND ip.sku_code=c.sku_code), day_result AS (")
.append("SELECT v.*,CASE WHEN #{p.salesKnown}=1 AND unit_valid=1 AND COALESCE(sales_unit,1)=1 THEN CASE WHEN quantity IS NOT NULL THEN quantity WHEN coverage>0 AND evidence<=CONVERT_TZ(CAST(business_date AS DATETIME),'+08:00','+00:00') THEN 0 END END observed,")
.append("CASE WHEN coverage=1 AND unit_valid=1 AND COALESCE(sales_unit,1)=1 AND (quantity IS NOT NULL OR evidence<=CONVERT_TZ(CAST(business_date AS DATETIME),'+08:00','+00:00')) THEN 1 ELSE 0 END complete,")
.append("CASE WHEN #{p.salesKnown}=1 AND coverage=1 AND COALESCE(sales_unit,1)=1 THEN 1 ELSE 0 END owner_complete,")
.append("CASE WHEN #{p.salesKnown}=1 AND COALESCE(sales_unit,1)=1 THEN CASE WHEN quantity IS NOT NULL THEN quantity WHEN coverage>0 THEN 0 END END owner_observed FROM daily_values v), sku_windows AS (")
.append("SELECT customer_code,sku_code").append(windowAggregates(false)).append(",COUNT(CASE WHEN business_date>=CAST(#{p.baseFrom} AS DATE) THEN sample_physical END) sample_count,")
.append("CASE WHEN COUNT(CASE WHEN business_date>=CAST(#{p.baseFrom} AS DATE) THEN sample_physical END)=#{p.query.days} THEN SUM(CASE WHEN business_date>=CAST(#{p.baseFrom} AS DATE) THEN sample_physical END)/#{p.query.days} END average_physical,")
.append("GROUP_CONCAT(CASE WHEN business_date>=CAST(#{p.baseFrom} AS DATE) AND sample_physical IS NULL THEN CAST(business_date AS CHAR) END ORDER BY business_date SEPARATOR ',') missing_dates ")
.append("FROM day_result GROUP BY customer_code,sku_code), last_sales AS (SELECT customer_code,sku_code,MAX(business_date) last_outbound FROM ll_selfop_sku_daily_sales WHERE ")
.append("FROM candidates c LEFT JOIN fixed_profiles f ON f.customer_code=c.customer_code AND f.sku_code=c.sku_code GROUP BY c.customer_code,c.sku_code)")
.append(skuWindows()).append(", last_sales AS (SELECT customer_code,sku_code,MAX(business_date) last_outbound FROM ll_selfop_sku_daily_sales WHERE ")
.append(scope("")).append(" AND sales_run_id=#{p.salesRun} AND business_date<CAST(#{p.until} AS DATE) AND outbound_quantity>0 AND quantity_unit='PCS' GROUP BY customer_code,sku_code)");
sql.append(", sku_base AS (SELECT c.customer_code,c.sku_code,c.product_name,c.evidence,c.unit_valid");
for(int n:List.of(7,15,30)) for(String suffix:List.of("outbound","observed","complete","partial")) sql.append(",w.w").append(n).append('_').append(suffix);
sql.append(",w.sample_count,w.average_physical,w.missing_dates,ls.last_outbound");
sql.append(",w.sample_count,w.average_physical,w.sample_mask,ls.last_outbound");
for(String field:List.of("physical","available","frozen","defective")) sql.append(",CASE WHEN #{p.stockFresh}=1 AND ip.quantity_unit='PCS' THEN st.").append(field).append(" END ").append(field);
sql.append(" FROM profiles c JOIN sku_windows w ON w.customer_code=c.customer_code AND w.sku_code=c.sku_code LEFT JOIN last_sales ls ON ls.customer_code=c.customer_code AND ls.sku_code=c.sku_code LEFT JOIN stocks st ON st.snapshot_run_id=#{p.inventoryRun} AND st.customer_code=c.customer_code AND st.sku_code=c.sku_code ")
.append("LEFT JOIN fixed_profiles ip ON ip.profile_run_id=#{p.inventoryRun} AND ip.customer_code=c.customer_code AND ip.sku_code=c.sku_code), sku_calculated AS (SELECT b.*,")
@@ -82,26 +81,95 @@ public final class InventoryTurnoverSql {
.append(p.query.days()).append("_outbound=0 AND unassessable=0 THEN 0 END slow FROM sku_calculated b) ");
return sql.toString();
}
private static String windowAggregates(boolean owner) {
private static String skuWindows() {
// One shared suffix table qualifies absent sales dates. Millisecond evidence
// after a midnight selects the next midnight, never the truncated same date.
var sql=new StringBuilder(", evidence_boundaries AS (SELECT start_utc,LAG(start_utc) OVER (ORDER BY start_utc) previous_start");
for(int n:List.of(7,15,30)) for(String kind:List.of("complete","known","partial")) {
String coverage=switch(kind){case "complete"->"coverage=1";case "known"->"coverage>0";default->"coverage=2";};
sql.append(",SUM(CASE WHEN business_date>=CAST(#{p.from").append(n).append("} AS DATE) AND ").append(coverage)
.append(" THEN 1 ELSE 0 END) OVER (ORDER BY start_utc ROWS BETWEEN CURRENT ROW AND UNBOUNDED FOLLOWING) w").append(n).append('_').append(kind);
}
sql.append(" FROM calendar), sku_zero_counts AS (SELECT c.customer_code,c.sku_code");
for(int n:List.of(7,15,30)) for(String kind:List.of("complete","known","partial"))
sql.append(",CASE WHEN c.unit_valid=1").append("complete".equals(kind)?"":" AND #{p.salesKnown}=1")
.append(" THEN COALESCE(b.w").append(n).append('_').append(kind).append(",0) ELSE 0 END w").append(n).append('_').append(kind);
sql.append(" FROM profiles c LEFT JOIN evidence_boundaries b ON c.evidence<=b.start_utc AND (b.previous_start IS NULL OR c.evidence>b.previous_start)), actual_sku_days AS (")
.append("SELECT s.customer_code,s.sku_code,s.business_date,CASE WHEN #{p.salesKnown}=1 AND c.unit_valid=1 AND s.unit_valid=1 THEN s.quantity END observed,")
.append("CASE WHEN d.coverage=1 AND c.unit_valid=1 AND s.unit_valid=1 THEN 1 ELSE 0 END complete,")
.append("CASE WHEN d.coverage=1 AND c.unit_valid=1 AND c.evidence<=d.start_utc THEN 1 ELSE 0 END zero_complete,")
.append("CASE WHEN #{p.salesKnown}=1 AND c.unit_valid=1 AND d.coverage>0 AND c.evidence<=d.start_utc THEN 1 ELSE 0 END zero_known,")
.append("CASE WHEN #{p.salesKnown}=1 AND c.unit_valid=1 AND d.coverage=2 AND c.evidence<=d.start_utc THEN 1 ELSE 0 END zero_partial ")
.append("FROM sales_days s JOIN profiles c ON c.customer_code=s.customer_code AND c.sku_code=s.sku_code JOIN calendar d ON d.business_date=s.business_date), sku_actual_counts AS (SELECT customer_code,sku_code");
for(int n:List.of(7,15,30)) {
String range="business_date>=CAST(#{p.from"+n+"} AS DATE)";
sql.append(",SUM(CASE WHEN ").append(range).append(" THEN COALESCE(observed,0) ELSE 0 END) w").append(n).append("_sum")
.append(",SUM(CASE WHEN ").append(range).append(" THEN complete-zero_complete ELSE 0 END) w").append(n).append("_complete")
.append(",SUM(CASE WHEN ").append(range).append(" THEN (CASE WHEN observed IS NOT NULL THEN 1 ELSE 0 END)-zero_known ELSE 0 END) w").append(n).append("_known")
.append(",SUM(CASE WHEN ").append(range).append(" THEN (CASE WHEN observed IS NOT NULL AND complete=0 THEN 1 ELSE 0 END)-zero_partial ELSE 0 END) w").append(n).append("_partial");
}
// Read only actual qualified samples at the frozen date/run. Missing candidates
// remain in sku_zero_counts; absence never creates a zero-valued sample.
sql.append(" FROM actual_sku_days GROUP BY customer_code,sku_code), sku_sample_days AS (SELECT st.customer_code,st.sku_code,d.business_date,")
.append("st.physical sample_physical FROM calendar d JOIN stocks st ON st.snapshot_run_id=d.sample_run ")
.append("JOIN fixed_profiles ip ON ip.profile_run_id=d.sample_run AND ip.customer_code=st.customer_code AND ip.sku_code=st.sku_code ")
.append("WHERE ip.quantity_unit='PCS' AND st.physical IS NOT NULL), sku_sample_counts AS (SELECT customer_code,sku_code,")
.append("COUNT(CASE WHEN business_date>=CAST(#{p.baseFrom} AS DATE) THEN sample_physical END) sample_count,")
.append("CASE WHEN COUNT(CASE WHEN business_date>=CAST(#{p.baseFrom} AS DATE) THEN sample_physical END)=#{p.query.days} THEN SUM(CASE WHEN business_date>=CAST(#{p.baseFrom} AS DATE) THEN sample_physical END)/#{p.query.days} END average_physical,")
.append(sampleMask()).append(" sample_mask FROM sku_sample_days GROUP BY customer_code,sku_code), sku_window_counts AS (SELECT z.customer_code,z.sku_code,COALESCE(s.sample_count,0) sample_count,s.average_physical,COALESCE(s.sample_mask,0) sample_mask");
for(int n:List.of(7,15,30)) sql.append(",CASE WHEN z.w").append(n).append("_known+COALESCE(a.w").append(n).append("_known,0)>0 THEN COALESCE(a.w").append(n).append("_sum,0) END w").append(n).append("_observed")
.append(",z.w").append(n).append("_complete+COALESCE(a.w").append(n).append("_complete,0) w").append(n).append("_complete")
.append(",z.w").append(n).append("_partial+COALESCE(a.w").append(n).append("_partial,0) w").append(n).append("_partial");
return sql.append(" FROM sku_zero_counts z LEFT JOIN sku_actual_counts a ON a.customer_code=z.customer_code AND a.sku_code=z.sku_code ")
.append("LEFT JOIN sku_sample_counts s ON s.customer_code=z.customer_code AND s.sku_code=z.sku_code), sku_windows AS (SELECT w.*")
.append(formalWindows()).append(" FROM sku_window_counts w)").toString();
}
private static String sampleMask() {
// Exactly 30 bits, all exactly representable even by POWER's numeric result.
return "SUM(CASE WHEN sample_physical IS NOT NULL THEN CAST(POWER(2,TIMESTAMPDIFF(DAY,CAST(#{p.from} AS DATE),business_date)) AS SIGNED) ELSE 0 END)";
}
private static String pageMissingDates() {
// Only the selected page expands dates. Numeric qualification and filtering
// already used every candidate and every frozen sample before pagination.
return ", page_missing AS (SELECT r.*, (SELECT GROUP_CONCAT(CAST(business_date AS CHAR) ORDER BY business_date SEPARATOR ',') FROM calendar d "
+"WHERE d.business_date>=CAST(#{p.baseFrom} AS DATE) AND MOD(FLOOR(r.sample_mask/POWER(2,TIMESTAMPDIFF(DAY,CAST(#{p.from} AS DATE),d.business_date))),2)=0) missing_dates FROM page_result r)";
}
private static String windowAggregates() {
StringBuilder sql=new StringBuilder();
for(int n:List.of(7,15,30)) {
String range="business_date>=CAST(#{p.from"+n+"} AS DATE)";
sql.append(",CASE WHEN SUM(CASE WHEN ").append(range).append(" THEN complete ELSE 0 END)=").append(n)
.append(" THEN SUM(CASE WHEN ").append(range).append(" THEN COALESCE(observed,0) END) END w").append(n).append("_outbound")
.append(",SUM(CASE WHEN ").append(range).append(" THEN observed END) w").append(n).append("_observed")
sql.append(",SUM(CASE WHEN ").append(range).append(" THEN observed END) w").append(n).append("_observed")
.append(",SUM(CASE WHEN ").append(range).append(" THEN complete ELSE 0 END) w").append(n).append("_complete")
.append(",SUM(CASE WHEN ").append(range).append(" AND complete=0 AND observed IS NOT NULL THEN 1 ELSE 0 END) w").append(n).append("_partial");
}
return sql.toString();
}
private static String formalWindows() {
// Derive formal values once per SKU/owner, reusing the same complete count and
// observed sum. A complete all-null observation sum retains the prior zero;
// partial/unknown windows remain null and never shorten the denominator.
var sql=new StringBuilder();
for(int n:List.of(7,15,30)) sql.append(",CASE WHEN w.w").append(n).append("_complete=").append(n)
.append(" THEN COALESCE(w.w").append(n).append("_observed,0) END w").append(n).append("_outbound");
return sql.toString();
}
private static String ownerCte(Input p) {
return ", owner_days AS (SELECT customer_code,business_date,MIN(owner_complete) complete,"
+"SUM(owner_observed) observed,"
+"CASE WHEN COUNT(sample_physical)=COUNT(*) THEN SUM(sample_physical) END sample_physical FROM day_result GROUP BY customer_code,business_date), owner_windows AS (SELECT customer_code"
+windowAggregates(true)+",COUNT(CASE WHEN business_date>=CAST(#{p.baseFrom} AS DATE) THEN sample_physical END) sample_count,"
// Sales units apply to actual daily records, not profile units/evidence.
// The full candidate count distinguishes covered absent rows (known zero)
// from a day where every candidate has only an invalid actual record.
return ", owner_candidates AS (SELECT customer_code,COUNT(*) candidate_count FROM candidates GROUP BY customer_code), owner_actual_days AS ("
+"SELECT customer_code,business_date,COUNT(*) actual_count,SUM(CASE WHEN unit_valid=1 THEN 1 ELSE 0 END) valid_count,"
+"SUM(CASE WHEN unit_valid=1 THEN quantity END) observed FROM sales_days GROUP BY customer_code,business_date), owner_sample_days AS ("
+"SELECT s.customer_code,s.business_date,SUM(s.sample_physical) sample_physical "
+"FROM sku_sample_days s JOIN owner_candidates c ON c.customer_code=s.customer_code GROUP BY s.customer_code,s.business_date HAVING COUNT(*)=MAX(c.candidate_count)), owner_days AS ("
+"SELECT c.customer_code,d.business_date,CASE WHEN #{p.salesKnown}=1 AND d.coverage=1 AND COALESCE(a.actual_count-a.valid_count,0)=0 THEN 1 ELSE 0 END complete,"
+"CASE WHEN #{p.salesKnown}=1 THEN CASE WHEN a.valid_count>0 THEN a.observed WHEN d.coverage>0 AND c.candidate_count>COALESCE(a.actual_count,0) THEN 0 END END observed,"
+"s.sample_physical FROM owner_candidates c CROSS JOIN calendar d LEFT JOIN owner_actual_days a ON a.customer_code=c.customer_code AND a.business_date=d.business_date "
+"LEFT JOIN owner_sample_days s ON s.customer_code=c.customer_code AND s.business_date=d.business_date), owner_window_counts AS (SELECT customer_code"
+windowAggregates()+",COUNT(CASE WHEN business_date>=CAST(#{p.baseFrom} AS DATE) THEN sample_physical END) sample_count,"
+"CASE WHEN COUNT(CASE WHEN business_date>=CAST(#{p.baseFrom} AS DATE) THEN sample_physical END)=#{p.query.days} THEN SUM(CASE WHEN business_date>=CAST(#{p.baseFrom} AS DATE) THEN sample_physical END)/#{p.query.days} END average_physical,"
+"GROUP_CONCAT(CASE WHEN business_date>=CAST(#{p.baseFrom} AS DATE) AND sample_physical IS NULL THEN CAST(business_date AS CHAR) END ORDER BY business_date SEPARATOR ',') missing_dates FROM owner_days GROUP BY customer_code), owner_totals AS ("
+totals("customer_code",true)+" FROM sku_result GROUP BY customer_code), owner_result AS (SELECT t.*,w.sample_count,w.average_physical,w.missing_dates,"
+sampleMask()+" sample_mask FROM owner_days GROUP BY customer_code), owner_windows AS (SELECT w.*"+formalWindows()+" FROM owner_window_counts w), owner_totals AS ("
+totals("customer_code",true)+" FROM sku_result GROUP BY customer_code), owner_result AS (SELECT t.*,w.sample_count,w.average_physical,w.sample_mask,"
+"CASE WHEN w.average_physical>0 THEN w.w"+p.query.days()+"_outbound/w.average_physical END turnover,"
+String.join(",",List.of(7,15,30).stream().flatMap(n->List.of("outbound","observed","complete","partial").stream().map(s->"w.w"+n+"_"+s)).toList())
+" FROM owner_totals t JOIN owner_windows w ON w.customer_code=t.customer_code) ";
@@ -140,7 +208,7 @@ public final class InventoryTurnoverSql {
}
public static String page(Map<String,Object> args) {
Input p=(Input)args.get("p");boolean owner="OWNER".equals(p.query.group());
return cte(p)+(owner?ownerCte(p):"")+"SELECT * FROM "+(owner?"owner_result":"sku_result")+filter(p,owner)+order(p,owner)+" LIMIT #{p.query.pageSize} OFFSET #{p.query.offset}";
return cte(p)+(owner?ownerCte(p):"")+", page_result AS (SELECT * FROM "+(owner?"owner_result":"sku_result")+filter(p,owner)+order(p,owner)+" LIMIT #{p.query.pageSize} OFFSET #{p.query.offset})"+pageMissingDates()+" SELECT * FROM page_missing"+order(p,owner);
}
public static String count(Map<String,Object> args) {
Input p=(Input)args.get("p");boolean owner="OWNER".equals(p.query.group());
@@ -155,10 +223,10 @@ public final class InventoryTurnoverSql {
+"SELECT 'OWNER' kind,customer_code,physical,0 unknown_count FROM ranked_owners UNION ALL SELECT 'META' kind,NULL customer_code,NULL physical,COUNT(*) unknown_count FROM owner_result WHERE physical IS NULL ORDER BY kind DESC,physical DESC,customer_code";
}
public static String chartWindows(Map<String,Object> args) {
Input p=(Input)args.get("p");return cte(p)+", warehouse_days AS (SELECT d.business_date,"
Input p=(Input)args.get("p");return "WITH calendar AS ("+calendar(p)+"), sales_days AS ("+salesDays()+"), warehouse_days AS (SELECT d.business_date,"
+"CASE WHEN #{p.salesKnown}=1 AND d.coverage=1 AND MIN(COALESCE(s.unit_valid,1))=1 THEN 1 ELSE 0 END complete,"
+"CASE WHEN #{p.salesKnown}=1 THEN CASE WHEN COUNT(s.business_date)=0 AND d.coverage>0 THEN 0 ELSE SUM(CASE WHEN s.unit_valid=1 THEN s.quantity END) END END observed "
+"FROM calendar d LEFT JOIN sales_days s ON s.business_date=d.business_date GROUP BY d.business_date,d.coverage) SELECT COUNT(*) day_count"+windowAggregates(true)+" FROM warehouse_days";
+"FROM calendar d LEFT JOIN sales_days s ON s.business_date=d.business_date GROUP BY d.business_date,d.coverage), warehouse_window_counts AS (SELECT COUNT(*) day_count"+windowAggregates()+" FROM warehouse_days) SELECT w.*"+formalWindows()+" FROM warehouse_window_counts w";
}
private static String jsonFields(List<String> fields) {
return "JSON_OBJECT("+String.join(",",fields.stream().map(f->"'"+f+"',"+f).toList())+")";
@@ -174,17 +242,21 @@ public final class InventoryTurnoverSql {
for(String field:List.of("physical","available","frozen","defective"))for(String suffix:List.of("known","unknown"))fields.add(field+"_"+suffix);
for(String risk:List.of("no_outbound","slow"))for(String suffix:List.of("count","physical","unknown"))fields.add(risk+"_"+suffix);
} else fields.addAll(List.of("sku_code","product_name","coverage_days","no_outbound","slow"));
String sql=cte(p)+(owner||overview?ownerCte(p):"")
// The physical-stock chart needs owner totals, not owner sales/sample windows.
String sql=cte(p)+(owner?ownerCte(p):overview?", owner_totals AS ("+totals("customer_code",true)+" FROM sku_result GROUP BY customer_code) ":"")
+", page_result AS (SELECT r.*,ROW_NUMBER() OVER ("+order(p,owner)+") ordinal FROM "+source+" r"+filter(p,owner)+order(p,owner)+" LIMIT #{p.query.pageSize} OFFSET #{p.query.offset})";
if(overview)sql+=", summary_result AS ("+totals(null,false)+" FROM sku_result), top_owners AS (SELECT customer_code,physical,ROW_NUMBER() OVER (ORDER BY physical DESC,customer_code) ordinal FROM owner_result WHERE physical IS NOT NULL ORDER BY physical DESC,customer_code LIMIT 10)";
sql+=" SELECT 'ROW' section,ordinal,"+jsonFields(fields)+" payload FROM page_result"
sql+=pageMissingDates();
if(overview)sql+=", summary_result AS ("+totals(null,false)+" FROM sku_result), top_owners AS (SELECT customer_code,physical,ROW_NUMBER() OVER (ORDER BY physical DESC,customer_code) ordinal FROM owner_totals WHERE physical IS NOT NULL ORDER BY physical DESC,customer_code LIMIT 10)";
// Statement-local only: share intermediate relations across report branches;
// do not change connection/global settings or any result/filter semantics.
sql+=" SELECT /*+ SET_VAR(optimizer_switch='derived_merge=off') SET_VAR(optimizer_search_depth=4) */ 'ROW' section,ordinal,"+jsonFields(fields)+" payload FROM page_missing"
+" UNION ALL SELECT 'TOTAL' section,0 ordinal,JSON_OBJECT('total',COUNT(*)) payload FROM "+source+filter(p,owner);
if(overview) {
List<String> summary=new ArrayList<>(List.of("sku_count","unassessable","no_outbound_count","no_outbound_unknown"));
for(String field:List.of("physical","available")){summary.add(field);summary.add(field+"_known");summary.add(field+"_unknown");}
sql+=" UNION ALL SELECT 'OVERVIEW' section,0 ordinal,"+jsonFields(summary)+" payload FROM summary_result"
+" UNION ALL SELECT 'OWNER' section,ordinal,JSON_OBJECT('customer_code',customer_code,'physical',physical) payload FROM top_owners"
+" UNION ALL SELECT 'OWNER_META' section,0 ordinal,JSON_OBJECT('unknown_count',COUNT(*)) payload FROM owner_result WHERE physical IS NULL";
+" UNION ALL SELECT 'OWNER_META' section,0 ordinal,JSON_OBJECT('unknown_count',COUNT(*)) payload FROM owner_totals WHERE physical IS NULL";
}
return sql+" ORDER BY section,ordinal";
}