1627 lines
44 KiB
SQL
1627 lines
44 KiB
SQL
-- Databricks notebook source
|
|
-- MAGIC %md
|
|
-- MAGIC # CHPA 01/02 refactor validation (DWD/DWS)
|
|
-- MAGIC
|
|
-- MAGIC Run this notebook AFTER all `sql/chpa/01_dwd/` and `sql/chpa/02_dws/` jobs
|
|
-- MAGIC finish and BEFORE migrating downstream consumers.
|
|
-- MAGIC
|
|
-- MAGIC **Snapshot assumption:** the legacy CHPA 01/02 jobs and the new RE 01_dwd/02_dws
|
|
-- MAGIC jobs must have run on the same source snapshot (same DWD sources, same config
|
|
-- MAGIC tables, same fact files). The legacy tables below are kept as validation
|
|
-- MAGIC baselines until migration completes.
|
|
-- MAGIC
|
|
-- MAGIC **Hard gates:** row counts and bidirectional `EXCEPT ALL` on explicit business
|
|
-- MAGIC columns (regenerated `ETL_*_DT` timestamps are excluded) for every
|
|
-- MAGIC logic-equivalent old/new pair. Any failed check raises an error at the end.
|
|
-- MAGIC
|
|
-- MAGIC **Intentional soft areas** (quality metrics only, no hard failure):
|
|
-- MAGIC
|
|
-- MAGIC 1. **Sales fact province (Part 2) rows** -- the province mapping was rewritten:
|
|
-- MAGIC legacy normalized province names from `dm.dm_td_geography` (CONCAT suffixes);
|
|
-- MAGIC the new fact joins `dwd_gnd_pharbers_prov_fact.PROVINCE_C` directly to
|
|
-- MAGIC `dws.dws_ext_td_ims_geo.PROVINCE_C` (layer fix). Exact equality is only
|
|
-- MAGIC guaranteed when geo coverage is identical, so only the national (CHT) rows
|
|
-- MAGIC are hard-gated; province rows are reported via match-rate and delta metrics.
|
|
-- MAGIC 2. **Market** -- the legacy MERGE could abort on multi-match
|
|
-- MAGIC (`DELTA_MULTIPLE_SOURCE_ROW_MATCHING`) and `ROW_NUMBER()` KC tie-breaks are
|
|
-- MAGIC engine-defined; equivalence is expected in every non-error case but is not
|
|
-- MAGIC guaranteed, so market is metrics-only.
|
|
-- MAGIC 3. **ETL timestamps** -- regenerated by each run; reported as informational
|
|
-- MAGIC metrics only.
|
|
-- MAGIC
|
|
-- MAGIC Target initialization is documented in each build script: most use `LIKE` the
|
|
-- MAGIC verified baseline, explicit narrowed contracts use zero-row CTAS type inference,
|
|
-- MAGIC and the stateful pack-YM table uses `DEEP CLONE` to retain older history.
|
|
|
|
-- COMMAND ----------
|
|
|
|
-- Manufacturer-corporation schema contract: the legacy dwd_ims_td_manufacturer_corp
|
|
-- carries T1.* plus 3 derived columns; only the columns referenced by live
|
|
-- consumers are known locally. Confirm the 9-column contract below before relying
|
|
-- on the manufacturer-corporation gate (the DWS build script documents this
|
|
-- UNKNOWN-SCHEMA caveat).
|
|
DESCRIBE TABLE dws.dws_ext_td_ims_manufacturer_corporation;
|
|
|
|
-- COMMAND ----------
|
|
|
|
DESCRIBE TABLE dwd.dwd_ims_td_manufacturer_corp;
|
|
|
|
-- COMMAND ----------
|
|
|
|
-- Manufacturer-corporation: known columns only (6 source + 3 derived).
|
|
CREATE OR REPLACE TEMP VIEW validation_old_manufacturer_corp AS
|
|
SELECT
|
|
Manufacturer_ID,
|
|
Manufacturer_CODE,
|
|
Manufacturer_Abbr,
|
|
Manufacturer_Name,
|
|
ManufacturerType_ID,
|
|
Corporation_Code,
|
|
CORP_MASTER_CODE,
|
|
CORP_ABBR,
|
|
CORP_DES
|
|
FROM dwd.dwd_ims_td_manufacturer_corp;
|
|
|
|
-- COMMAND ----------
|
|
|
|
CREATE OR REPLACE TEMP VIEW validation_new_manufacturer_corp AS
|
|
SELECT
|
|
Manufacturer_ID,
|
|
Manufacturer_CODE,
|
|
Manufacturer_Abbr,
|
|
Manufacturer_Name,
|
|
ManufacturerType_ID,
|
|
Corporation_Code,
|
|
CORP_MASTER_CODE,
|
|
CORP_ABBR,
|
|
CORP_DES
|
|
FROM dws.dws_ext_td_ims_manufacturer_corporation;
|
|
|
|
-- COMMAND ----------
|
|
|
|
-- Pack property: 31 business columns (no timestamps in the contract).
|
|
CREATE OR REPLACE TEMP VIEW validation_old_pack_property AS
|
|
SELECT
|
|
PACK_COD,
|
|
PACK_DES,
|
|
STGH_DES,
|
|
PACK_LCH,
|
|
PROD_COD,
|
|
CMPS_COD,
|
|
CMPS_DES,
|
|
ATC1_COD,
|
|
ATC2_COD,
|
|
ATC3_COD,
|
|
ATC4_COD,
|
|
APP1_COD,
|
|
APP2_COD,
|
|
APP3_COD,
|
|
BIO_DESC,
|
|
GENE_ORIG_DESC,
|
|
ETH_OTC_DESC,
|
|
NRDL_DESC,
|
|
NRDL_Entry_Date,
|
|
EDL_DESC,
|
|
TCM_DESC,
|
|
PAED_DESC,
|
|
GQCE_DESC,
|
|
VBP_DESC,
|
|
MANU_COD,
|
|
MANU_DES,
|
|
MNFL_COD,
|
|
MNFL_DES,
|
|
CORP_COD,
|
|
CORP_DES,
|
|
BrandType
|
|
FROM dwd.dwd_ims_td_pack_property;
|
|
|
|
-- COMMAND ----------
|
|
|
|
CREATE OR REPLACE TEMP VIEW validation_new_pack_property AS
|
|
SELECT
|
|
PACK_COD,
|
|
PACK_DES,
|
|
STGH_DES,
|
|
PACK_LCH,
|
|
PROD_COD,
|
|
CMPS_COD,
|
|
CMPS_DES,
|
|
ATC1_COD,
|
|
ATC2_COD,
|
|
ATC3_COD,
|
|
ATC4_COD,
|
|
APP1_COD,
|
|
APP2_COD,
|
|
APP3_COD,
|
|
BIO_DESC,
|
|
GENE_ORIG_DESC,
|
|
ETH_OTC_DESC,
|
|
NRDL_DESC,
|
|
NRDL_Entry_Date,
|
|
EDL_DESC,
|
|
TCM_DESC,
|
|
PAED_DESC,
|
|
GQCE_DESC,
|
|
VBP_DESC,
|
|
MANU_COD,
|
|
MANU_DES,
|
|
MNFL_COD,
|
|
MNFL_DES,
|
|
CORP_COD,
|
|
CORP_DES,
|
|
BrandType
|
|
FROM dws.dws_ext_td_ims_pack_property;
|
|
|
|
-- COMMAND ----------
|
|
|
|
-- Geo: 9 business columns. ETL_INSERT_DT/ETL_UPDATE_DT are copied from staging by
|
|
-- both jobs; they are compared as informational metrics only (see timestamp cell).
|
|
CREATE OR REPLACE TEMP VIEW validation_old_geo AS
|
|
SELECT
|
|
AUDIT_COD,
|
|
AUDIT_DES,
|
|
AUDIT_DES_C,
|
|
AUDIT_TYPE,
|
|
CITY_TIER,
|
|
AZ_CITY_TIER,
|
|
PROVINCE,
|
|
PROVINCE_C,
|
|
REGIONCENTER
|
|
FROM dws.dws_ims_td_geo;
|
|
|
|
-- COMMAND ----------
|
|
|
|
CREATE OR REPLACE TEMP VIEW validation_new_geo AS
|
|
SELECT
|
|
AUDIT_COD,
|
|
AUDIT_DES,
|
|
AUDIT_DES_C,
|
|
AUDIT_TYPE,
|
|
CITY_TIER,
|
|
AZ_CITY_TIER,
|
|
PROVINCE,
|
|
PROVINCE_C,
|
|
REGIONCENTER
|
|
FROM dws.dws_ext_td_ims_geo;
|
|
|
|
-- COMMAND ----------
|
|
|
|
-- Corporation CN: 3 business columns (ETL timestamps regenerated).
|
|
CREATE OR REPLACE TEMP VIEW validation_old_corp_cn AS
|
|
SELECT
|
|
CORP_COD,
|
|
CORP_DES,
|
|
CORP_DES_C
|
|
FROM dws.dws_ims_td_corp_cn;
|
|
|
|
-- COMMAND ----------
|
|
|
|
CREATE OR REPLACE TEMP VIEW validation_new_corp_cn AS
|
|
SELECT
|
|
CORP_COD,
|
|
CORP_DES,
|
|
CORP_DES_C
|
|
FROM dws.dws_ext_td_ims_corporation_cn;
|
|
|
|
-- COMMAND ----------
|
|
|
|
-- Manufacturer CN: 3 business columns (ETL timestamps regenerated).
|
|
CREATE OR REPLACE TEMP VIEW validation_old_manu_cn AS
|
|
SELECT
|
|
MANU_COD,
|
|
MANU_DES,
|
|
MANU_DES_C
|
|
FROM dws.dws_ims_td_manu_cn;
|
|
|
|
-- COMMAND ----------
|
|
|
|
CREATE OR REPLACE TEMP VIEW validation_new_manu_cn AS
|
|
SELECT
|
|
MANU_COD,
|
|
MANU_DES,
|
|
MANU_DES_C
|
|
FROM dws.dws_ext_td_ims_manufacturer_cn;
|
|
|
|
-- COMMAND ----------
|
|
|
|
-- Product CN: 5 business columns incl. RANK_TYPE (declarative CASE replaces the
|
|
-- legacy tmp list + UPDATE; equivalence chains through the multi-manufacturer check).
|
|
CREATE OR REPLACE TEMP VIEW validation_old_prod_cn AS
|
|
SELECT
|
|
PROD_COD,
|
|
PROD_DES,
|
|
PROD_DES_C,
|
|
CMPS_DES_C,
|
|
RANK_TYPE
|
|
FROM dws.dws_ims_td_prod_cn;
|
|
|
|
-- COMMAND ----------
|
|
|
|
CREATE OR REPLACE TEMP VIEW validation_new_prod_cn AS
|
|
SELECT
|
|
PROD_COD,
|
|
PROD_DES,
|
|
PROD_DES_C,
|
|
CMPS_DES_C,
|
|
RANK_TYPE
|
|
FROM dws.dws_ext_td_ims_product_cn;
|
|
|
|
-- COMMAND ----------
|
|
|
|
-- ATC CN: 12 business columns (legacy ATC2_CODe/ATC3_CODe/ATC4_CODe typo'd names
|
|
-- resolve case-insensitively to ATC2_CODE/ATC3_CODE/ATC4_CODE).
|
|
CREATE OR REPLACE TEMP VIEW validation_old_atc_cn AS
|
|
SELECT
|
|
ATC1_COD,
|
|
ATC1_DES,
|
|
ATC1_DES_C,
|
|
ATC2_COD,
|
|
ATC2_DES,
|
|
ATC2_DES_C,
|
|
ATC3_COD,
|
|
ATC3_DES,
|
|
ATC3_DES_C,
|
|
ATC4_COD,
|
|
ATC4_DES,
|
|
ATC4_DES_C
|
|
FROM dws.dws_ims_td_atc_cn;
|
|
|
|
-- COMMAND ----------
|
|
|
|
CREATE OR REPLACE TEMP VIEW validation_new_atc_cn AS
|
|
SELECT
|
|
ATC1_COD,
|
|
ATC1_DES,
|
|
ATC1_DES_C,
|
|
ATC2_COD,
|
|
ATC2_DES,
|
|
ATC2_DES_C,
|
|
ATC3_COD,
|
|
ATC3_DES,
|
|
ATC3_DES_C,
|
|
ATC4_COD,
|
|
ATC4_DES,
|
|
ATC4_DES_C
|
|
FROM dws.dws_ext_td_ims_atc_cn;
|
|
|
|
-- COMMAND ----------
|
|
|
|
-- NFC CN: 9 business columns.
|
|
CREATE OR REPLACE TEMP VIEW validation_old_nfc_cn AS
|
|
SELECT
|
|
APP1_COD,
|
|
APP1_DES,
|
|
APP1_DES_C,
|
|
APP2_COD,
|
|
APP2_DES,
|
|
APP2_DES_C,
|
|
APP3_COD,
|
|
APP3_DES,
|
|
APP3_DES_C
|
|
FROM dws.dws_ims_td_nfc_cn;
|
|
|
|
-- COMMAND ----------
|
|
|
|
CREATE OR REPLACE TEMP VIEW validation_new_nfc_cn AS
|
|
SELECT
|
|
APP1_COD,
|
|
APP1_DES,
|
|
APP1_DES_C,
|
|
APP2_COD,
|
|
APP2_DES,
|
|
APP2_DES_C,
|
|
APP3_COD,
|
|
APP3_DES,
|
|
APP3_DES_C
|
|
FROM dws.dws_ext_td_ims_nfc_cn;
|
|
|
|
-- COMMAND ----------
|
|
|
|
-- Market-TA: legacy SELECT * is replaced by an explicit MARKET/TA projection; if the
|
|
-- source map carries additional columns they are intentionally not compared.
|
|
CREATE OR REPLACE TEMP VIEW validation_old_market_ta AS
|
|
SELECT
|
|
MARKET,
|
|
TA
|
|
FROM dws.dws_ims_td_market_ta;
|
|
|
|
-- COMMAND ----------
|
|
|
|
CREATE OR REPLACE TEMP VIEW validation_new_market_ta AS
|
|
SELECT
|
|
MARKET,
|
|
TA
|
|
FROM dws.dws_ext_td_ims_market_ta;
|
|
|
|
-- COMMAND ----------
|
|
|
|
-- Product multi-manufacturer list: legacy tmp staging vs new DWS flag list (PROD_COD only).
|
|
CREATE OR REPLACE TEMP VIEW validation_old_prod_tmp AS
|
|
SELECT
|
|
PROD_COD
|
|
FROM tmp.tmp_ims_td_prod_tmp;
|
|
|
|
-- COMMAND ----------
|
|
|
|
CREATE OR REPLACE TEMP VIEW validation_new_prod_multi AS
|
|
SELECT
|
|
PROD_COD
|
|
FROM dws.dws_ext_td_ims_product_multi_manufacturer;
|
|
|
|
-- COMMAND ----------
|
|
|
|
-- Pack-YM rolling snapshot: 3 business columns (ym, pack_id, pack_code).
|
|
CREATE OR REPLACE TEMP VIEW validation_old_pack_ym AS
|
|
SELECT
|
|
ym,
|
|
pack_id,
|
|
pack_code
|
|
FROM dws.dws_ims_td_pack_ym;
|
|
|
|
-- COMMAND ----------
|
|
|
|
CREATE OR REPLACE TEMP VIEW validation_new_pack_ym AS
|
|
SELECT
|
|
ym,
|
|
pack_id,
|
|
pack_code
|
|
FROM dws.dws_ext_td_ims_pack_ym;
|
|
|
|
-- COMMAND ----------
|
|
|
|
-- Promoted sales fact (full): 9 business columns, no timestamps.
|
|
CREATE OR REPLACE TEMP VIEW validation_old_fact AS
|
|
SELECT
|
|
YM,
|
|
AUDIT_COD,
|
|
PACK_COD,
|
|
MTH00LC,
|
|
MTH00LCLY,
|
|
MTH00CN,
|
|
MTH00CNLY,
|
|
MTH00UN,
|
|
MTH00UNLY
|
|
FROM tmp.tmp_ims_tf_fact_sales;
|
|
|
|
-- COMMAND ----------
|
|
|
|
CREATE OR REPLACE TEMP VIEW validation_new_fact AS
|
|
SELECT
|
|
YM,
|
|
AUDIT_COD,
|
|
PACK_COD,
|
|
MTH00LC,
|
|
MTH00LCLY,
|
|
MTH00CN,
|
|
MTH00CNLY,
|
|
MTH00UN,
|
|
MTH00UNLY
|
|
FROM dws.dws_ext_tf_ims_chpa_sales;
|
|
|
|
-- COMMAND ----------
|
|
|
|
-- National (CHT) rows only: logic-equivalent by construction (same join keys, same
|
|
-- asymmetric YM>=202201 window, same yearmont_range cap); hard-gated below.
|
|
CREATE OR REPLACE TEMP VIEW validation_old_fact_cht AS
|
|
SELECT
|
|
YM,
|
|
AUDIT_COD,
|
|
PACK_COD,
|
|
MTH00LC,
|
|
MTH00LCLY,
|
|
MTH00CN,
|
|
MTH00CNLY,
|
|
MTH00UN,
|
|
MTH00UNLY
|
|
FROM validation_old_fact
|
|
WHERE AUDIT_COD = 'CHT';
|
|
|
|
-- COMMAND ----------
|
|
|
|
CREATE OR REPLACE TEMP VIEW validation_new_fact_cht AS
|
|
SELECT
|
|
YM,
|
|
AUDIT_COD,
|
|
PACK_COD,
|
|
MTH00LC,
|
|
MTH00LCLY,
|
|
MTH00CN,
|
|
MTH00CNLY,
|
|
MTH00UN,
|
|
MTH00UNLY
|
|
FROM validation_new_fact
|
|
WHERE AUDIT_COD = 'CHT';
|
|
|
|
-- COMMAND ----------
|
|
|
|
-- Date dimension: 7 business columns (chained on fact equivalence; the YM range and
|
|
-- DATE_FLAG max come from the fact, which is validated above).
|
|
CREATE OR REPLACE TEMP VIEW validation_old_date AS
|
|
SELECT
|
|
YM,
|
|
YEAR,
|
|
MONTH,
|
|
QUARTER,
|
|
YQ,
|
|
DATE_FLAG,
|
|
HALF_YEAR
|
|
FROM dws.dws_ims_td_date;
|
|
|
|
-- COMMAND ----------
|
|
|
|
CREATE OR REPLACE TEMP VIEW validation_new_date AS
|
|
SELECT
|
|
YM,
|
|
YEAR,
|
|
MONTH,
|
|
QUARTER,
|
|
YQ,
|
|
DATE_FLAG,
|
|
HALF_YEAR
|
|
FROM dws.dws_ext_td_ims_date;
|
|
|
|
-- COMMAND ----------
|
|
|
|
-- Market: 35 business columns. Metrics-only area (see header), view kept for the
|
|
-- soft EXCEPT ALL comparison in the market quality cell.
|
|
CREATE OR REPLACE TEMP VIEW validation_old_market AS
|
|
SELECT
|
|
market,
|
|
PACK_COD,
|
|
PACK_DES,
|
|
STGH_DES,
|
|
PACK_LCH,
|
|
PROD_COD,
|
|
CMPS_COD,
|
|
CMPS_DES,
|
|
ATC1_COD,
|
|
ATC2_COD,
|
|
ATC3_COD,
|
|
ATC4_COD,
|
|
APP1_COD,
|
|
APP2_COD,
|
|
APP3_COD,
|
|
BIO_DESC,
|
|
GENE_ORIG_DESC,
|
|
ETH_OTC_DESC,
|
|
NRDL_DESC,
|
|
NRDL_Entry_Date,
|
|
EDL_DESC,
|
|
TCM_DESC,
|
|
PAED_DESC,
|
|
GQCE_DESC,
|
|
VBP_DESC,
|
|
MANU_COD,
|
|
MANU_DES,
|
|
MNFL_COD,
|
|
MNFL_DES,
|
|
CORP_COD,
|
|
CORP_DES,
|
|
BrandType,
|
|
bu,
|
|
Market_Ratio,
|
|
Key_Competitor
|
|
FROM dws.dws_ims_td_market;
|
|
|
|
-- COMMAND ----------
|
|
|
|
CREATE OR REPLACE TEMP VIEW validation_new_market AS
|
|
SELECT
|
|
market,
|
|
PACK_COD,
|
|
PACK_DES,
|
|
STGH_DES,
|
|
PACK_LCH,
|
|
PROD_COD,
|
|
CMPS_COD,
|
|
CMPS_DES,
|
|
ATC1_COD,
|
|
ATC2_COD,
|
|
ATC3_COD,
|
|
ATC4_COD,
|
|
APP1_COD,
|
|
APP2_COD,
|
|
APP3_COD,
|
|
BIO_DESC,
|
|
GENE_ORIG_DESC,
|
|
ETH_OTC_DESC,
|
|
NRDL_DESC,
|
|
NRDL_Entry_Date,
|
|
EDL_DESC,
|
|
TCM_DESC,
|
|
PAED_DESC,
|
|
GQCE_DESC,
|
|
VBP_DESC,
|
|
MANU_COD,
|
|
MANU_DES,
|
|
MNFL_COD,
|
|
MNFL_DES,
|
|
CORP_COD,
|
|
CORP_DES,
|
|
BrandType,
|
|
bu,
|
|
Market_Ratio,
|
|
Key_Competitor
|
|
FROM dws.dws_ext_td_ims_market;
|
|
|
|
-- COMMAND ----------
|
|
|
|
-- Hard compatibility checks: row counts + bidirectional EXCEPT ALL per area.
|
|
-- Every row must end with passed = true; the final cell raises on any failure.
|
|
CREATE OR REPLACE TEMP VIEW validation_01_02_compatibility_checks AS
|
|
WITH compatibility_checks AS (
|
|
SELECT
|
|
'manufacturer_corporation' AS area,
|
|
'manu_corp_row_count' AS check_name,
|
|
(SELECT COUNT(*) FROM validation_new_manufacturer_corp) AS actual_value,
|
|
(SELECT COUNT(*) FROM validation_old_manufacturer_corp) AS expected_value
|
|
UNION ALL
|
|
SELECT
|
|
'manufacturer_corporation',
|
|
'manu_corp_legacy_minus_new',
|
|
(
|
|
SELECT COUNT(*)
|
|
FROM (
|
|
SELECT * FROM validation_old_manufacturer_corp
|
|
EXCEPT ALL
|
|
SELECT * FROM validation_new_manufacturer_corp
|
|
) AS differences
|
|
),
|
|
0
|
|
UNION ALL
|
|
SELECT
|
|
'manufacturer_corporation',
|
|
'manu_corp_new_minus_legacy',
|
|
(
|
|
SELECT COUNT(*)
|
|
FROM (
|
|
SELECT * FROM validation_new_manufacturer_corp
|
|
EXCEPT ALL
|
|
SELECT * FROM validation_old_manufacturer_corp
|
|
) AS differences
|
|
),
|
|
0
|
|
UNION ALL
|
|
SELECT
|
|
'pack_property',
|
|
'pack_property_row_count',
|
|
(SELECT COUNT(*) FROM validation_new_pack_property),
|
|
(SELECT COUNT(*) FROM validation_old_pack_property)
|
|
UNION ALL
|
|
SELECT
|
|
'pack_property',
|
|
'pack_property_legacy_minus_new',
|
|
(
|
|
SELECT COUNT(*)
|
|
FROM (
|
|
SELECT * FROM validation_old_pack_property
|
|
EXCEPT ALL
|
|
SELECT * FROM validation_new_pack_property
|
|
) AS differences
|
|
),
|
|
0
|
|
UNION ALL
|
|
SELECT
|
|
'pack_property',
|
|
'pack_property_new_minus_legacy',
|
|
(
|
|
SELECT COUNT(*)
|
|
FROM (
|
|
SELECT * FROM validation_new_pack_property
|
|
EXCEPT ALL
|
|
SELECT * FROM validation_old_pack_property
|
|
) AS differences
|
|
),
|
|
0
|
|
UNION ALL
|
|
SELECT
|
|
'geo',
|
|
'geo_row_count',
|
|
(SELECT COUNT(*) FROM validation_new_geo),
|
|
(SELECT COUNT(*) FROM validation_old_geo)
|
|
UNION ALL
|
|
SELECT
|
|
'geo',
|
|
'geo_legacy_minus_new',
|
|
(
|
|
SELECT COUNT(*)
|
|
FROM (
|
|
SELECT * FROM validation_old_geo
|
|
EXCEPT ALL
|
|
SELECT * FROM validation_new_geo
|
|
) AS differences
|
|
),
|
|
0
|
|
UNION ALL
|
|
SELECT
|
|
'geo',
|
|
'geo_new_minus_legacy',
|
|
(
|
|
SELECT COUNT(*)
|
|
FROM (
|
|
SELECT * FROM validation_new_geo
|
|
EXCEPT ALL
|
|
SELECT * FROM validation_old_geo
|
|
) AS differences
|
|
),
|
|
0
|
|
UNION ALL
|
|
SELECT
|
|
'corporation_cn',
|
|
'corp_cn_row_count',
|
|
(SELECT COUNT(*) FROM validation_new_corp_cn),
|
|
(SELECT COUNT(*) FROM validation_old_corp_cn)
|
|
UNION ALL
|
|
SELECT
|
|
'corporation_cn',
|
|
'corp_cn_legacy_minus_new',
|
|
(
|
|
SELECT COUNT(*)
|
|
FROM (
|
|
SELECT * FROM validation_old_corp_cn
|
|
EXCEPT ALL
|
|
SELECT * FROM validation_new_corp_cn
|
|
) AS differences
|
|
),
|
|
0
|
|
UNION ALL
|
|
SELECT
|
|
'corporation_cn',
|
|
'corp_cn_new_minus_legacy',
|
|
(
|
|
SELECT COUNT(*)
|
|
FROM (
|
|
SELECT * FROM validation_new_corp_cn
|
|
EXCEPT ALL
|
|
SELECT * FROM validation_old_corp_cn
|
|
) AS differences
|
|
),
|
|
0
|
|
UNION ALL
|
|
SELECT
|
|
'manufacturer_cn',
|
|
'manu_cn_row_count',
|
|
(SELECT COUNT(*) FROM validation_new_manu_cn),
|
|
(SELECT COUNT(*) FROM validation_old_manu_cn)
|
|
UNION ALL
|
|
SELECT
|
|
'manufacturer_cn',
|
|
'manu_cn_legacy_minus_new',
|
|
(
|
|
SELECT COUNT(*)
|
|
FROM (
|
|
SELECT * FROM validation_old_manu_cn
|
|
EXCEPT ALL
|
|
SELECT * FROM validation_new_manu_cn
|
|
) AS differences
|
|
),
|
|
0
|
|
UNION ALL
|
|
SELECT
|
|
'manufacturer_cn',
|
|
'manu_cn_new_minus_legacy',
|
|
(
|
|
SELECT COUNT(*)
|
|
FROM (
|
|
SELECT * FROM validation_new_manu_cn
|
|
EXCEPT ALL
|
|
SELECT * FROM validation_old_manu_cn
|
|
) AS differences
|
|
),
|
|
0
|
|
UNION ALL
|
|
SELECT
|
|
'product_cn',
|
|
'prod_cn_row_count',
|
|
(SELECT COUNT(*) FROM validation_new_prod_cn),
|
|
(SELECT COUNT(*) FROM validation_old_prod_cn)
|
|
UNION ALL
|
|
SELECT
|
|
'product_cn',
|
|
'prod_cn_legacy_minus_new',
|
|
(
|
|
SELECT COUNT(*)
|
|
FROM (
|
|
SELECT * FROM validation_old_prod_cn
|
|
EXCEPT ALL
|
|
SELECT * FROM validation_new_prod_cn
|
|
) AS differences
|
|
),
|
|
0
|
|
UNION ALL
|
|
SELECT
|
|
'product_cn',
|
|
'prod_cn_new_minus_legacy',
|
|
(
|
|
SELECT COUNT(*)
|
|
FROM (
|
|
SELECT * FROM validation_new_prod_cn
|
|
EXCEPT ALL
|
|
SELECT * FROM validation_old_prod_cn
|
|
) AS differences
|
|
),
|
|
0
|
|
UNION ALL
|
|
SELECT
|
|
'atc_cn',
|
|
'atc_cn_row_count',
|
|
(SELECT COUNT(*) FROM validation_new_atc_cn),
|
|
(SELECT COUNT(*) FROM validation_old_atc_cn)
|
|
UNION ALL
|
|
SELECT
|
|
'atc_cn',
|
|
'atc_cn_legacy_minus_new',
|
|
(
|
|
SELECT COUNT(*)
|
|
FROM (
|
|
SELECT * FROM validation_old_atc_cn
|
|
EXCEPT ALL
|
|
SELECT * FROM validation_new_atc_cn
|
|
) AS differences
|
|
),
|
|
0
|
|
UNION ALL
|
|
SELECT
|
|
'atc_cn',
|
|
'atc_cn_new_minus_legacy',
|
|
(
|
|
SELECT COUNT(*)
|
|
FROM (
|
|
SELECT * FROM validation_new_atc_cn
|
|
EXCEPT ALL
|
|
SELECT * FROM validation_old_atc_cn
|
|
) AS differences
|
|
),
|
|
0
|
|
UNION ALL
|
|
SELECT
|
|
'nfc_cn',
|
|
'nfc_cn_row_count',
|
|
(SELECT COUNT(*) FROM validation_new_nfc_cn),
|
|
(SELECT COUNT(*) FROM validation_old_nfc_cn)
|
|
UNION ALL
|
|
SELECT
|
|
'nfc_cn',
|
|
'nfc_cn_legacy_minus_new',
|
|
(
|
|
SELECT COUNT(*)
|
|
FROM (
|
|
SELECT * FROM validation_old_nfc_cn
|
|
EXCEPT ALL
|
|
SELECT * FROM validation_new_nfc_cn
|
|
) AS differences
|
|
),
|
|
0
|
|
UNION ALL
|
|
SELECT
|
|
'nfc_cn',
|
|
'nfc_cn_new_minus_legacy',
|
|
(
|
|
SELECT COUNT(*)
|
|
FROM (
|
|
SELECT * FROM validation_new_nfc_cn
|
|
EXCEPT ALL
|
|
SELECT * FROM validation_old_nfc_cn
|
|
) AS differences
|
|
),
|
|
0
|
|
UNION ALL
|
|
SELECT
|
|
'market_ta',
|
|
'market_ta_row_count',
|
|
(SELECT COUNT(*) FROM validation_new_market_ta),
|
|
(SELECT COUNT(*) FROM validation_old_market_ta)
|
|
UNION ALL
|
|
SELECT
|
|
'market_ta',
|
|
'market_ta_legacy_minus_new',
|
|
(
|
|
SELECT COUNT(*)
|
|
FROM (
|
|
SELECT * FROM validation_old_market_ta
|
|
EXCEPT ALL
|
|
SELECT * FROM validation_new_market_ta
|
|
) AS differences
|
|
),
|
|
0
|
|
UNION ALL
|
|
SELECT
|
|
'market_ta',
|
|
'market_ta_new_minus_legacy',
|
|
(
|
|
SELECT COUNT(*)
|
|
FROM (
|
|
SELECT * FROM validation_new_market_ta
|
|
EXCEPT ALL
|
|
SELECT * FROM validation_old_market_ta
|
|
) AS differences
|
|
),
|
|
0
|
|
UNION ALL
|
|
SELECT
|
|
'product_multi_manufacturer',
|
|
'prod_multi_row_count',
|
|
(SELECT COUNT(*) FROM validation_new_prod_multi),
|
|
(SELECT COUNT(*) FROM validation_old_prod_tmp)
|
|
UNION ALL
|
|
SELECT
|
|
'product_multi_manufacturer',
|
|
'prod_multi_legacy_minus_new',
|
|
(
|
|
SELECT COUNT(*)
|
|
FROM (
|
|
SELECT * FROM validation_old_prod_tmp
|
|
EXCEPT ALL
|
|
SELECT * FROM validation_new_prod_multi
|
|
) AS differences
|
|
),
|
|
0
|
|
UNION ALL
|
|
SELECT
|
|
'product_multi_manufacturer',
|
|
'prod_multi_new_minus_legacy',
|
|
(
|
|
SELECT COUNT(*)
|
|
FROM (
|
|
SELECT * FROM validation_new_prod_multi
|
|
EXCEPT ALL
|
|
SELECT * FROM validation_old_prod_tmp
|
|
) AS differences
|
|
),
|
|
0
|
|
UNION ALL
|
|
SELECT
|
|
'pack_ym',
|
|
'pack_ym_row_count',
|
|
(SELECT COUNT(*) FROM validation_new_pack_ym),
|
|
(SELECT COUNT(*) FROM validation_old_pack_ym)
|
|
UNION ALL
|
|
SELECT
|
|
'pack_ym',
|
|
'pack_ym_legacy_minus_new',
|
|
(
|
|
SELECT COUNT(*)
|
|
FROM (
|
|
SELECT * FROM validation_old_pack_ym
|
|
EXCEPT ALL
|
|
SELECT * FROM validation_new_pack_ym
|
|
) AS differences
|
|
),
|
|
0
|
|
UNION ALL
|
|
SELECT
|
|
'pack_ym',
|
|
'pack_ym_new_minus_legacy',
|
|
(
|
|
SELECT COUNT(*)
|
|
FROM (
|
|
SELECT * FROM validation_new_pack_ym
|
|
EXCEPT ALL
|
|
SELECT * FROM validation_old_pack_ym
|
|
) AS differences
|
|
),
|
|
0
|
|
UNION ALL
|
|
SELECT
|
|
'sales_fact_cht',
|
|
'fact_cht_row_count',
|
|
(SELECT COUNT(*) FROM validation_new_fact_cht),
|
|
(SELECT COUNT(*) FROM validation_old_fact_cht)
|
|
UNION ALL
|
|
SELECT
|
|
'sales_fact_cht',
|
|
'fact_cht_legacy_minus_new',
|
|
(
|
|
SELECT COUNT(*)
|
|
FROM (
|
|
SELECT * FROM validation_old_fact_cht
|
|
EXCEPT ALL
|
|
SELECT * FROM validation_new_fact_cht
|
|
) AS differences
|
|
),
|
|
0
|
|
UNION ALL
|
|
SELECT
|
|
'sales_fact_cht',
|
|
'fact_cht_new_minus_legacy',
|
|
(
|
|
SELECT COUNT(*)
|
|
FROM (
|
|
SELECT * FROM validation_new_fact_cht
|
|
EXCEPT ALL
|
|
SELECT * FROM validation_old_fact_cht
|
|
) AS differences
|
|
),
|
|
0
|
|
UNION ALL
|
|
SELECT
|
|
'date',
|
|
'date_row_count',
|
|
(SELECT COUNT(*) FROM validation_new_date),
|
|
(SELECT COUNT(*) FROM validation_old_date)
|
|
UNION ALL
|
|
SELECT
|
|
'date',
|
|
'date_legacy_minus_new',
|
|
(
|
|
SELECT COUNT(*)
|
|
FROM (
|
|
SELECT * FROM validation_old_date
|
|
EXCEPT ALL
|
|
SELECT * FROM validation_new_date
|
|
) AS differences
|
|
),
|
|
0
|
|
UNION ALL
|
|
SELECT
|
|
'date',
|
|
'date_new_minus_legacy',
|
|
(
|
|
SELECT COUNT(*)
|
|
FROM (
|
|
SELECT * FROM validation_new_date
|
|
EXCEPT ALL
|
|
SELECT * FROM validation_old_date
|
|
) AS differences
|
|
),
|
|
0
|
|
UNION ALL
|
|
SELECT
|
|
'framework',
|
|
'except_all_null_semantics',
|
|
(
|
|
SELECT COUNT(*)
|
|
FROM (
|
|
SELECT CAST(NULL AS STRING) AS nullable_value
|
|
EXCEPT ALL
|
|
SELECT CAST(NULL AS STRING) AS nullable_value
|
|
) AS differences
|
|
),
|
|
0
|
|
)
|
|
SELECT
|
|
area,
|
|
check_name,
|
|
actual_value,
|
|
expected_value,
|
|
actual_value = expected_value AS passed
|
|
FROM compatibility_checks;
|
|
|
|
-- COMMAND ----------
|
|
|
|
SELECT
|
|
area,
|
|
check_name,
|
|
actual_value,
|
|
expected_value,
|
|
passed
|
|
FROM validation_01_02_compatibility_checks
|
|
ORDER BY area, check_name;
|
|
|
|
-- COMMAND ----------
|
|
|
|
-- Grain quality metrics on the NEW outputs (duplicate business keys / null required
|
|
-- keys). Review metrics, not hard failures.
|
|
WITH duplicated_keys AS (
|
|
SELECT
|
|
'pack_property' AS metric_name,
|
|
(
|
|
SELECT COUNT(*)
|
|
FROM (
|
|
SELECT PACK_COD
|
|
FROM validation_new_pack_property
|
|
GROUP BY PACK_COD
|
|
HAVING COUNT(*) > 1
|
|
) AS duplicates
|
|
) AS metric_value
|
|
UNION ALL
|
|
SELECT
|
|
'manu_corp_duplicate_manufacturer_id',
|
|
(
|
|
SELECT COUNT(*)
|
|
FROM (
|
|
SELECT Manufacturer_ID
|
|
FROM validation_new_manufacturer_corp
|
|
GROUP BY Manufacturer_ID
|
|
HAVING COUNT(*) > 1
|
|
) AS duplicates
|
|
)
|
|
UNION ALL
|
|
SELECT
|
|
'geo_duplicate_audit_cod',
|
|
(
|
|
SELECT COUNT(*)
|
|
FROM (
|
|
SELECT AUDIT_COD
|
|
FROM validation_new_geo
|
|
GROUP BY AUDIT_COD
|
|
HAVING COUNT(*) > 1
|
|
) AS duplicates
|
|
)
|
|
UNION ALL
|
|
SELECT
|
|
'corp_cn_duplicate_corp_cod',
|
|
(
|
|
SELECT COUNT(*)
|
|
FROM (
|
|
SELECT CORP_COD
|
|
FROM validation_new_corp_cn
|
|
GROUP BY CORP_COD
|
|
HAVING COUNT(*) > 1
|
|
) AS duplicates
|
|
)
|
|
UNION ALL
|
|
SELECT
|
|
'manu_cn_duplicate_manu_cod',
|
|
(
|
|
SELECT COUNT(*)
|
|
FROM (
|
|
SELECT MANU_COD
|
|
FROM validation_new_manu_cn
|
|
GROUP BY MANU_COD
|
|
HAVING COUNT(*) > 1
|
|
) AS duplicates
|
|
)
|
|
UNION ALL
|
|
SELECT
|
|
'prod_cn_duplicate_prod_cod',
|
|
(
|
|
SELECT COUNT(*)
|
|
FROM (
|
|
SELECT PROD_COD
|
|
FROM validation_new_prod_cn
|
|
GROUP BY PROD_COD
|
|
HAVING COUNT(*) > 1
|
|
) AS duplicates
|
|
)
|
|
UNION ALL
|
|
SELECT
|
|
'atc_cn_duplicate_path',
|
|
(
|
|
SELECT COUNT(*)
|
|
FROM (
|
|
SELECT ATC1_COD, ATC2_COD, ATC3_COD, ATC4_COD
|
|
FROM validation_new_atc_cn
|
|
GROUP BY ATC1_COD, ATC2_COD, ATC3_COD, ATC4_COD
|
|
HAVING COUNT(*) > 1
|
|
) AS duplicates
|
|
)
|
|
UNION ALL
|
|
SELECT
|
|
'nfc_cn_duplicate_path',
|
|
(
|
|
SELECT COUNT(*)
|
|
FROM (
|
|
SELECT APP1_COD, APP2_COD, APP3_COD
|
|
FROM validation_new_nfc_cn
|
|
GROUP BY APP1_COD, APP2_COD, APP3_COD
|
|
HAVING COUNT(*) > 1
|
|
) AS duplicates
|
|
)
|
|
UNION ALL
|
|
SELECT
|
|
'market_ta_duplicate_market_ta',
|
|
(
|
|
SELECT COUNT(*)
|
|
FROM (
|
|
SELECT MARKET, TA
|
|
FROM validation_new_market_ta
|
|
GROUP BY MARKET, TA
|
|
HAVING COUNT(*) > 1
|
|
) AS duplicates
|
|
)
|
|
UNION ALL
|
|
SELECT
|
|
'prod_multi_duplicate_prod_cod',
|
|
(
|
|
SELECT COUNT(*)
|
|
FROM (
|
|
SELECT PROD_COD
|
|
FROM validation_new_prod_multi
|
|
GROUP BY PROD_COD
|
|
HAVING COUNT(*) > 1
|
|
) AS duplicates
|
|
)
|
|
UNION ALL
|
|
SELECT
|
|
'pack_ym_duplicate_ym_pack_id',
|
|
(
|
|
SELECT COUNT(*)
|
|
FROM (
|
|
SELECT ym, pack_id
|
|
FROM validation_new_pack_ym
|
|
GROUP BY ym, pack_id
|
|
HAVING COUNT(*) > 1
|
|
) AS duplicates
|
|
)
|
|
UNION ALL
|
|
SELECT
|
|
'fact_duplicate_ym_audit_pack',
|
|
(
|
|
SELECT COUNT(*)
|
|
FROM (
|
|
SELECT YM, AUDIT_COD, PACK_COD
|
|
FROM validation_new_fact
|
|
GROUP BY YM, AUDIT_COD, PACK_COD
|
|
HAVING COUNT(*) > 1
|
|
) AS duplicates
|
|
)
|
|
UNION ALL
|
|
SELECT
|
|
'date_duplicate_ym',
|
|
(
|
|
SELECT COUNT(*)
|
|
FROM (
|
|
SELECT YM
|
|
FROM validation_new_date
|
|
GROUP BY YM
|
|
HAVING COUNT(*) > 1
|
|
) AS duplicates
|
|
)
|
|
UNION ALL
|
|
SELECT
|
|
'market_multi_kc_per_market_pack_prod',
|
|
(
|
|
SELECT COUNT(*)
|
|
FROM (
|
|
SELECT market, PACK_COD, PROD_COD
|
|
FROM validation_new_market
|
|
GROUP BY market, PACK_COD, PROD_COD
|
|
HAVING COUNT(DISTINCT Key_Competitor) > 1
|
|
) AS duplicates
|
|
)
|
|
)
|
|
SELECT
|
|
metric_name,
|
|
metric_value
|
|
FROM duplicated_keys
|
|
UNION ALL
|
|
SELECT
|
|
'pack_property_null_pack_cod',
|
|
COUNT_IF(PACK_COD IS NULL)
|
|
FROM validation_new_pack_property
|
|
UNION ALL
|
|
SELECT
|
|
'manu_corp_null_manufacturer_id',
|
|
COUNT_IF(Manufacturer_ID IS NULL)
|
|
FROM validation_new_manufacturer_corp
|
|
UNION ALL
|
|
SELECT
|
|
'geo_null_audit_cod',
|
|
COUNT_IF(AUDIT_COD IS NULL)
|
|
FROM validation_new_geo
|
|
UNION ALL
|
|
SELECT
|
|
'corp_cn_null_corp_cod',
|
|
COUNT_IF(CORP_COD IS NULL)
|
|
FROM validation_new_corp_cn
|
|
UNION ALL
|
|
SELECT
|
|
'manu_cn_null_manu_cod',
|
|
COUNT_IF(MANU_COD IS NULL)
|
|
FROM validation_new_manu_cn
|
|
UNION ALL
|
|
SELECT
|
|
'prod_cn_null_prod_cod',
|
|
COUNT_IF(PROD_COD IS NULL)
|
|
FROM validation_new_prod_cn
|
|
UNION ALL
|
|
SELECT
|
|
'atc_cn_null_atc1_cod',
|
|
COUNT_IF(ATC1_COD IS NULL)
|
|
FROM validation_new_atc_cn
|
|
UNION ALL
|
|
SELECT
|
|
'nfc_cn_null_app1_cod',
|
|
COUNT_IF(APP1_COD IS NULL)
|
|
FROM validation_new_nfc_cn
|
|
UNION ALL
|
|
SELECT
|
|
'market_ta_null_market',
|
|
COUNT_IF(MARKET IS NULL)
|
|
FROM validation_new_market_ta
|
|
UNION ALL
|
|
SELECT
|
|
'market_ta_null_ta',
|
|
COUNT_IF(TA IS NULL)
|
|
FROM validation_new_market_ta
|
|
UNION ALL
|
|
SELECT
|
|
'pack_ym_null_ym',
|
|
COUNT_IF(ym IS NULL)
|
|
FROM validation_new_pack_ym
|
|
UNION ALL
|
|
SELECT
|
|
'pack_ym_null_pack_id',
|
|
COUNT_IF(pack_id IS NULL)
|
|
FROM validation_new_pack_ym
|
|
UNION ALL
|
|
SELECT
|
|
'pack_ym_null_pack_code',
|
|
COUNT_IF(pack_code IS NULL)
|
|
FROM validation_new_pack_ym
|
|
UNION ALL
|
|
SELECT
|
|
'fact_null_pack_cod',
|
|
COUNT_IF(PACK_COD IS NULL)
|
|
FROM validation_new_fact
|
|
UNION ALL
|
|
SELECT
|
|
'fact_null_audit_cod',
|
|
COUNT_IF(AUDIT_COD IS NULL)
|
|
FROM validation_new_fact
|
|
UNION ALL
|
|
SELECT
|
|
'date_null_ym',
|
|
COUNT_IF(YM IS NULL)
|
|
FROM validation_new_date
|
|
UNION ALL
|
|
SELECT
|
|
'market_null_market',
|
|
COUNT_IF(market IS NULL)
|
|
FROM validation_new_market
|
|
UNION ALL
|
|
SELECT
|
|
'market_null_pack_cod',
|
|
COUNT_IF(PACK_COD IS NULL)
|
|
FROM validation_new_market
|
|
ORDER BY metric_name;
|
|
|
|
-- COMMAND ----------
|
|
|
|
-- Geo province match-rate: how much of the Pharbers province fact is covered by the
|
|
-- new dws_ext_td_ims_geo PROVINCE_C mapping (the layer fix replaced the legacy
|
|
-- dm.dm_td_geography CONCAT normalization). Unmatched provinces produce NULL
|
|
-- AUDIT_COD in the fact and must be reviewed.
|
|
SELECT
|
|
(SELECT COUNT(DISTINCT province_c) FROM dwd.dwd_gnd_pharbers_prov_fact) AS total_distinct_provinces,
|
|
(
|
|
SELECT COUNT(*)
|
|
FROM (
|
|
SELECT DISTINCT province_c
|
|
FROM dwd.dwd_gnd_pharbers_prov_fact
|
|
WHERE province_c IN (SELECT province_c FROM validation_new_geo)
|
|
) AS matched
|
|
) AS matched_distinct_provinces,
|
|
(
|
|
SELECT COUNT(*)
|
|
FROM (
|
|
SELECT DISTINCT province_c
|
|
FROM dwd.dwd_gnd_pharbers_prov_fact
|
|
WHERE province_c IN (SELECT province_c FROM validation_new_geo)
|
|
) AS matched
|
|
) / NULLIF(
|
|
(SELECT COUNT(DISTINCT province_c) FROM dwd.dwd_gnd_pharbers_prov_fact),
|
|
0
|
|
) AS province_match_rate,
|
|
(SELECT COUNT(*) FROM dwd.dwd_gnd_pharbers_prov_fact) AS total_fact_rows,
|
|
(
|
|
SELECT COUNT(*)
|
|
FROM dwd.dwd_gnd_pharbers_prov_fact
|
|
WHERE province_c IN (SELECT province_c FROM validation_new_geo)
|
|
) AS matched_fact_rows,
|
|
(
|
|
SELECT COUNT(*)
|
|
FROM dwd.dwd_gnd_pharbers_prov_fact
|
|
WHERE province_c IN (SELECT province_c FROM validation_new_geo)
|
|
) / NULLIF(
|
|
(SELECT COUNT(*) FROM dwd.dwd_gnd_pharbers_prov_fact),
|
|
0
|
|
) AS row_match_rate;
|
|
|
|
-- COMMAND ----------
|
|
|
|
-- Unmatched provinces (present in the fact but missing from dws_ext_td_ims_geo):
|
|
-- these rows become NULL AUDIT_COD groups in the promoted fact. Review list.
|
|
SELECT
|
|
province_c
|
|
FROM (
|
|
SELECT DISTINCT province_c
|
|
FROM dwd.dwd_gnd_pharbers_prov_fact
|
|
EXCEPT ALL
|
|
SELECT province_c
|
|
FROM validation_new_geo
|
|
) AS unmatched
|
|
ORDER BY province_c
|
|
LIMIT 50;
|
|
|
|
-- COMMAND ----------
|
|
|
|
-- Sales fact province (Part 2) metrics. NOT hard-gated: the province mapping was
|
|
-- rewritten (geo layer fix), so per-row equality is not guaranteed. Large deltas or
|
|
-- a jump in NULL AUDIT_COD rows indicate a geo coverage regression to review.
|
|
SELECT
|
|
(SELECT COUNT(*) FROM validation_old_fact WHERE AUDIT_COD IS NULL OR AUDIT_COD <> 'CHT') AS old_province_rows,
|
|
(SELECT COUNT(*) FROM validation_new_fact WHERE AUDIT_COD IS NULL OR AUDIT_COD <> 'CHT') AS new_province_rows,
|
|
(SELECT COUNT_IF(AUDIT_COD IS NULL) FROM validation_old_fact) AS old_null_audit_rows,
|
|
(SELECT COUNT_IF(AUDIT_COD IS NULL) FROM validation_new_fact) AS new_null_audit_rows,
|
|
(SELECT COUNT_IF(PACK_COD IS NULL) FROM validation_old_fact) AS old_null_pack_rows,
|
|
(SELECT COUNT_IF(PACK_COD IS NULL) FROM validation_new_fact) AS new_null_pack_rows,
|
|
(SELECT COUNT(*) FROM validation_old_fact) AS old_fact_total_rows,
|
|
(SELECT COUNT(*) FROM validation_new_fact) AS new_fact_total_rows,
|
|
(SELECT SUM(MTH00UN) FROM validation_old_fact WHERE AUDIT_COD IS NULL OR AUDIT_COD <> 'CHT') AS old_province_mth00un,
|
|
(SELECT SUM(MTH00UN) FROM validation_new_fact WHERE AUDIT_COD IS NULL OR AUDIT_COD <> 'CHT') AS new_province_mth00un,
|
|
(
|
|
SELECT SUM(MTH00UN)
|
|
FROM validation_new_fact
|
|
WHERE AUDIT_COD IS NULL OR AUDIT_COD <> 'CHT'
|
|
) - (
|
|
SELECT SUM(MTH00UN)
|
|
FROM validation_old_fact
|
|
WHERE AUDIT_COD IS NULL OR AUDIT_COD <> 'CHT'
|
|
) AS province_mth00un_delta,
|
|
(
|
|
SELECT SUM(MTH00LC)
|
|
FROM validation_new_fact
|
|
WHERE AUDIT_COD IS NULL OR AUDIT_COD <> 'CHT'
|
|
) - (
|
|
SELECT SUM(MTH00LC)
|
|
FROM validation_old_fact
|
|
WHERE AUDIT_COD IS NULL OR AUDIT_COD <> 'CHT'
|
|
) AS province_mth00lc_delta;
|
|
|
|
-- COMMAND ----------
|
|
|
|
-- Pack-YM rolling window metrics: the recent 5-year window (ym + 500 > max ym) is
|
|
-- refreshed every run; older rows are retained unchanged. Compare window extents.
|
|
SELECT
|
|
(SELECT MAX(ym) FROM validation_old_pack_ym) AS old_max_ym,
|
|
(SELECT MAX(ym) FROM validation_new_pack_ym) AS new_max_ym,
|
|
(
|
|
SELECT COUNT(*)
|
|
FROM validation_old_pack_ym
|
|
WHERE ym + 500 > (SELECT MAX(ym) FROM validation_old_pack_ym)
|
|
) AS old_window_rows,
|
|
(
|
|
SELECT COUNT(*)
|
|
FROM validation_new_pack_ym
|
|
WHERE ym + 500 > (SELECT MAX(ym) FROM validation_new_pack_ym)
|
|
) AS new_window_rows,
|
|
(
|
|
SELECT COUNT(*)
|
|
FROM validation_old_pack_ym
|
|
WHERE ym + 500 <= (SELECT MAX(ym) FROM validation_old_pack_ym)
|
|
) AS old_retained_rows,
|
|
(
|
|
SELECT COUNT(*)
|
|
FROM validation_new_pack_ym
|
|
WHERE ym + 500 <= (SELECT MAX(ym) FROM validation_new_pack_ym)
|
|
) AS new_retained_rows,
|
|
(SELECT COUNT(DISTINCT ym) FROM validation_old_pack_ym) AS old_distinct_ym,
|
|
(SELECT COUNT(DISTINCT ym) FROM validation_new_pack_ym) AS new_distinct_ym;
|
|
|
|
-- COMMAND ----------
|
|
|
|
-- Date dimension metrics (hard EXCEPT ALL already gates equality).
|
|
SELECT
|
|
(SELECT COUNT(*) FROM validation_old_date) AS old_rows,
|
|
(SELECT COUNT(*) FROM validation_new_date) AS new_rows,
|
|
(SELECT MAX(YM) FROM validation_old_date) AS old_max_ym,
|
|
(SELECT MAX(YM) FROM validation_new_date) AS new_max_ym,
|
|
(SELECT COUNT_IF(DATE_FLAG = 'R') FROM validation_old_date) AS old_report_month_rows,
|
|
(SELECT COUNT_IF(DATE_FLAG = 'R') FROM validation_new_date) AS new_report_month_rows;
|
|
|
|
-- COMMAND ----------
|
|
|
|
-- Market quality metrics. NOT hard-gated: the legacy MERGE could abort on multi-match
|
|
-- and KC ROW_NUMBER tie-breaks are engine-defined; the anti-join rewrite matches the
|
|
-- MERGE result in every non-error case. The soft EXCEPT ALL counts below must be 0
|
|
-- for a clean run -- treat any difference as a review item, not an automatic failure.
|
|
SELECT
|
|
(SELECT COUNT(*) FROM validation_old_market) AS old_rows,
|
|
(SELECT COUNT(*) FROM validation_new_market) AS new_rows,
|
|
(
|
|
SELECT COUNT(*)
|
|
FROM (
|
|
SELECT * FROM validation_old_market
|
|
EXCEPT ALL
|
|
SELECT * FROM validation_new_market
|
|
) AS differences
|
|
) AS market_legacy_minus_new,
|
|
(
|
|
SELECT COUNT(*)
|
|
FROM (
|
|
SELECT * FROM validation_new_market
|
|
EXCEPT ALL
|
|
SELECT * FROM validation_old_market
|
|
) AS differences
|
|
) AS market_new_minus_legacy,
|
|
(SELECT COUNT_IF(Market_Ratio = '1') FROM validation_old_market) AS old_ratio_one_rows,
|
|
(SELECT COUNT_IF(Market_Ratio = '1') FROM validation_new_market) AS new_ratio_one_rows,
|
|
(SELECT COUNT_IF(Key_Competitor = 'Others') FROM validation_old_market) AS old_kc_others_rows,
|
|
(SELECT COUNT_IF(Key_Competitor = 'Others') FROM validation_new_market) AS new_kc_others_rows;
|
|
|
|
-- COMMAND ----------
|
|
|
|
-- ETL timestamp metrics (informational only): ETL_INSERT_DT/ETL_UPDATE_DT are
|
|
-- regenerated by each run, so differences are expected except for geo, which copies
|
|
-- the staging timestamps unchanged. Counts rows whose ETL_INSERT_DT differs between
|
|
-- the old baseline and the new table on the business key.
|
|
SELECT
|
|
'geo' AS table_name,
|
|
'etl_insert_mismatch_rows' AS metric_name,
|
|
(
|
|
SELECT COUNT(*)
|
|
FROM dws.dws_ims_td_geo AS old_t
|
|
JOIN dws.dws_ext_td_ims_geo AS new_t
|
|
ON old_t.AUDIT_COD = new_t.AUDIT_COD
|
|
WHERE NOT (old_t.ETL_INSERT_DT = new_t.ETL_INSERT_DT)
|
|
) AS metric_value
|
|
UNION ALL
|
|
SELECT
|
|
'corporation_cn',
|
|
'etl_insert_mismatch_rows',
|
|
(
|
|
SELECT COUNT(*)
|
|
FROM dws.dws_ims_td_corp_cn AS old_t
|
|
JOIN dws.dws_ext_td_ims_corporation_cn AS new_t
|
|
ON old_t.CORP_COD = new_t.CORP_COD
|
|
WHERE NOT (old_t.ETL_INSERT_DT = new_t.ETL_INSERT_DT)
|
|
)
|
|
UNION ALL
|
|
SELECT
|
|
'manufacturer_cn',
|
|
'etl_insert_mismatch_rows',
|
|
(
|
|
SELECT COUNT(*)
|
|
FROM dws.dws_ims_td_manu_cn AS old_t
|
|
JOIN dws.dws_ext_td_ims_manufacturer_cn AS new_t
|
|
ON old_t.MANU_COD = new_t.MANU_COD
|
|
WHERE NOT (old_t.ETL_INSERT_DT = new_t.ETL_INSERT_DT)
|
|
)
|
|
UNION ALL
|
|
SELECT
|
|
'product_cn',
|
|
'etl_insert_mismatch_rows',
|
|
(
|
|
SELECT COUNT(*)
|
|
FROM dws.dws_ims_td_prod_cn AS old_t
|
|
JOIN dws.dws_ext_td_ims_product_cn AS new_t
|
|
ON old_t.PROD_COD = new_t.PROD_COD
|
|
WHERE NOT (old_t.ETL_INSERT_DT = new_t.ETL_INSERT_DT)
|
|
)
|
|
UNION ALL
|
|
SELECT
|
|
'atc_cn',
|
|
'etl_insert_mismatch_rows',
|
|
(
|
|
SELECT COUNT(*)
|
|
FROM dws.dws_ims_td_atc_cn AS old_t
|
|
JOIN dws.dws_ext_td_ims_atc_cn AS new_t
|
|
ON old_t.ATC1_COD = new_t.ATC1_COD
|
|
AND old_t.ATC2_COD = new_t.ATC2_COD
|
|
AND old_t.ATC3_COD = new_t.ATC3_COD
|
|
AND old_t.ATC4_COD = new_t.ATC4_COD
|
|
WHERE NOT (old_t.ETL_INSERT_DT = new_t.ETL_INSERT_DT)
|
|
)
|
|
UNION ALL
|
|
SELECT
|
|
'nfc_cn',
|
|
'etl_insert_mismatch_rows',
|
|
(
|
|
SELECT COUNT(*)
|
|
FROM dws.dws_ims_td_nfc_cn AS old_t
|
|
JOIN dws.dws_ext_td_ims_nfc_cn AS new_t
|
|
ON old_t.APP1_COD = new_t.APP1_COD
|
|
AND old_t.APP2_COD = new_t.APP2_COD
|
|
AND old_t.APP3_COD = new_t.APP3_COD
|
|
WHERE NOT (old_t.ETL_INSERT_DT = new_t.ETL_INSERT_DT)
|
|
)
|
|
UNION ALL
|
|
SELECT
|
|
'date',
|
|
'etl_insert_mismatch_rows',
|
|
(
|
|
SELECT COUNT(*)
|
|
FROM dws.dws_ims_td_date AS old_t
|
|
JOIN dws.dws_ext_td_ims_date AS new_t
|
|
ON old_t.YM = new_t.YM
|
|
WHERE NOT (old_t.ETL_INSERT_DT = new_t.ETL_INSERT_DT)
|
|
)
|
|
UNION ALL
|
|
SELECT
|
|
'pack_ym',
|
|
'etl_insert_mismatch_rows',
|
|
(
|
|
SELECT COUNT(*)
|
|
FROM dws.dws_ims_td_pack_ym AS old_t
|
|
JOIN dws.dws_ext_td_ims_pack_ym AS new_t
|
|
ON old_t.ym = new_t.ym
|
|
AND old_t.pack_id = new_t.pack_id
|
|
WHERE NOT (old_t.ETL_INSERT_DT = new_t.ETL_INSERT_DT)
|
|
)
|
|
UNION ALL
|
|
SELECT
|
|
'market',
|
|
'etl_insert_mismatch_rows',
|
|
(
|
|
SELECT COUNT(*)
|
|
FROM dws.dws_ims_td_market AS old_t
|
|
JOIN dws.dws_ext_td_ims_market AS new_t
|
|
ON old_t.market = new_t.market
|
|
AND old_t.PACK_COD = new_t.PACK_COD
|
|
AND old_t.PROD_COD = new_t.PROD_COD
|
|
WHERE NOT (old_t.ETL_INSERT_DT = new_t.ETL_INSERT_DT)
|
|
)
|
|
ORDER BY table_name;
|
|
|
|
-- COMMAND ----------
|
|
|
|
-- Block downstream migration when any hard compatibility check fails.
|
|
SELECT IF(
|
|
(SELECT COUNT_IF(NOT passed) FROM validation_01_02_compatibility_checks) = 0,
|
|
'All 01/02 refactor compatibility checks passed.',
|
|
raise_error(
|
|
CONCAT(
|
|
'01/02 refactor compatibility validation failed: ',
|
|
CAST((SELECT COUNT_IF(NOT passed) FROM validation_01_02_compatibility_checks) AS STRING),
|
|
' check(s) did not pass.'
|
|
)
|
|
)
|
|
) AS validation_result;
|
|
|
|
-- COMMAND ----------
|
|
|
|
-- Coverage report: hard checks per area (all must show failed = 0).
|
|
SELECT
|
|
area,
|
|
COUNT(*) AS checks,
|
|
COUNT_IF(passed) AS passed,
|
|
COUNT_IF(NOT passed) AS failed
|
|
FROM validation_01_02_compatibility_checks
|
|
GROUP BY area
|
|
ORDER BY area;
|
|
|
|
-- COMMAND ----------
|
|
|
|
-- MAGIC %md
|
|
-- MAGIC # Coverage and caveats
|
|
-- MAGIC
|
|
-- MAGIC ## Hard-gated areas (row count + bidirectional EXCEPT ALL, ETL timestamps excluded)
|
|
-- MAGIC
|
|
-- MAGIC | Area | Old baseline | New target | Business columns |
|
|
-- MAGIC | --- | --- | --- | --- |
|
|
-- MAGIC | manufacturer-corporation | dwd.dwd_ims_td_manufacturer_corp | dws.dws_ext_td_ims_manufacturer_corporation | 9 known columns |
|
|
-- MAGIC | pack property | dwd.dwd_ims_td_pack_property | dws.dws_ext_td_ims_pack_property | 31 |
|
|
-- MAGIC | geo | dws.dws_ims_td_geo | dws.dws_ext_td_ims_geo | 9 business + ETL as metric |
|
|
-- MAGIC | corporation CN | dws.dws_ims_td_corp_cn | dws.dws_ext_td_ims_corporation_cn | 3 |
|
|
-- MAGIC | manufacturer CN | dws.dws_ims_td_manu_cn | dws.dws_ext_td_ims_manufacturer_cn | 3 |
|
|
-- MAGIC | product CN (incl. RANK_TYPE) | dws.dws_ims_td_prod_cn | dws.dws_ext_td_ims_product_cn | 5 |
|
|
-- MAGIC | ATC CN | dws.dws_ims_td_atc_cn | dws.dws_ext_td_ims_atc_cn | 12 |
|
|
-- MAGIC | NFC CN | dws.dws_ims_td_nfc_cn | dws.dws_ext_td_ims_nfc_cn | 9 |
|
|
-- MAGIC | market-TA | dws.dws_ims_td_market_ta | dws.dws_ext_td_ims_market_ta | 2 |
|
|
-- MAGIC | product multi-manufacturer | tmp.tmp_ims_td_prod_tmp | dws.dws_ext_td_ims_product_multi_manufacturer | 1 |
|
|
-- MAGIC | pack-YM rolling window | dws.dws_ims_td_pack_ym | dws.dws_ext_td_ims_pack_ym | 3 |
|
|
-- MAGIC | sales fact (national CHT rows) | tmp.tmp_ims_tf_fact_sales | dws.dws_ext_tf_ims_chpa_sales | 9 |
|
|
-- MAGIC | date | dws.dws_ims_td_date | dws.dws_ext_td_ims_date | 7 |
|
|
-- MAGIC
|
|
-- MAGIC ## Metrics-only areas (documented reasons, no hard failure)
|
|
-- MAGIC
|
|
-- MAGIC - **Sales fact province rows**: geo layer fix changed the province join from
|
|
-- MAGIC `dm.dm_td_geography` CONCAT normalization to a direct
|
|
-- MAGIC `dws.dws_ext_td_ims_geo.PROVINCE_C` match. Province match-rate, NULL AUDIT_COD
|
|
-- MAGIC rows and value deltas are reported; a low match-rate or a large delta must be
|
|
-- MAGIC reviewed before migration.
|
|
-- MAGIC - **Market**: legacy MERGE multi-match failure modes and engine-defined
|
|
-- MAGIC `ROW_NUMBER()` KC tie-breaks mean equality is expected but not guaranteed; row
|
|
-- MAGIC counts, soft EXCEPT ALL counts, Market_Ratio = '1' share and KC 'Others' share
|
|
-- MAGIC are reported for review.
|
|
-- MAGIC - **ETL timestamps**: regenerated every run; mismatch counts are informational.
|
|
-- MAGIC - **01_dwd in-place jobs** (code padding, market config refresh, time-window
|
|
-- MAGIC defaults, ManufacturerType_ID fix, Pharbers ingest) write the same physical
|
|
-- MAGIC tables as the legacy CHPA 01 jobs, so no old/new comparison applies; their
|
|
-- MAGIC effect is covered transitively through the DWS outputs above.
|
|
-- MAGIC
|
|
-- MAGIC ## Known limitations
|
|
-- MAGIC
|
|
-- MAGIC - Manufacturer-corporation compares only the 9 columns referenced by live
|
|
-- MAGIC consumers; the legacy `T1.*` may carry additional columns not compared
|
|
-- MAGIC (UNKNOWN-SCHEMA caveat -- DESCRIBE the source before go-live).
|
|
-- MAGIC - market-TA compares only MARKET/TA; legacy `SELECT *` may carry extra source
|
|
-- MAGIC columns that are intentionally not carried into the new table.
|
|
-- MAGIC - All comparisons assume the old and new jobs ran on the same source snapshot;
|
|
-- MAGIC rerun the full old/new chain on the same snapshot before trusting the gate.
|
|
-- MAGIC - `EXCEPT ALL` NULL semantics are asserted by the framework guard; if that check
|
|
-- MAGIC fails, this engine does not compare NULLs as equal and the bidirectional
|
|
-- MAGIC checks cannot be trusted.
|