Files
tehran_taj/docs/migration-precheck-2.sql
T

182 lines
11 KiB
SQL
Raw Normal View History

-- ============================================================================
-- پیش‌بررسی دوم — سه سؤال باز
-- ============================================================================
--
-- ⚠️ مثل فایل اول: فقط SELECT COUNT / SUM. صفر INSERT/UPDATE/DELETE.
-- هیچ ستون متنی در خروجی نیست.
--
-- اجرا:
-- mysql -u USER -p -h HOST -P 3305 oapi < migration-precheck-2.sql > out2.txt
--
-- مرجع: docs/DATA-MIGRATION-MAP.md §۱۰.۴ · §۱۰.۶
-- ============================================================================
-- ---------------------------------------------------------------------------
-- 🔴 سؤال ۱ (مسدودکننده) — مبلغ سند مالی در کدام ستون است؟
--
-- در خروجی اول، SUM(cashes.remain) و SUM(cashes.rial_remain) هر دو NULL
-- برگشتند — یعنی در هر ۶۴۸ ردیف NULL هستند. پس مبلغ جای دیگری است.
-- بدون جواب این، LedgerEntry.amount خالی پر می‌شود و کل دفتر مالی
-- بی‌مبلغ منتقل می‌شود.
-- ---------------------------------------------------------------------------
SELECT '=== 1. WHERE IS THE LEDGER AMOUNT? ===' AS section;
-- هر ستون عددی cashes: چند ردیف مقدار غیرNULL و غیرصفر دارند؟
SELECT 'input' AS col, COUNT(input) AS not_null, SUM(input <> 0) AS nonzero FROM cashes WHERE deleted_at IS NULL
UNION ALL SELECT 'output', COUNT(output), SUM(output <> 0) FROM cashes WHERE deleted_at IS NULL
UNION ALL SELECT 'remain', COUNT(remain), SUM(remain <> 0) FROM cashes WHERE deleted_at IS NULL
UNION ALL SELECT 'rial_input', COUNT(rial_input), SUM(rial_input <> 0) FROM cashes WHERE deleted_at IS NULL
UNION ALL SELECT 'rial_output', COUNT(rial_output), SUM(rial_output <> 0) FROM cashes WHERE deleted_at IS NULL
UNION ALL SELECT 'rial_remain', COUNT(rial_remain), SUM(rial_remain <> 0) FROM cashes WHERE deleted_at IS NULL
UNION ALL SELECT 'value', COUNT(value), SUM(value <> 0) FROM cashes WHERE deleted_at IS NULL
UNION ALL SELECT 'original_value', COUNT(original_value), SUM(original_value <> 0) FROM cashes WHERE deleted_at IS NULL
UNION ALL SELECT 'balance', COUNT(balance), SUM(balance <> 0) FROM cashes WHERE deleted_at IS NULL
UNION ALL SELECT 'price', COUNT(price), SUM(price <> 0) FROM cashes WHERE deleted_at IS NULL
UNION ALL SELECT 'price_per_gram', COUNT(price_per_gram), SUM(price_per_gram <> 0) FROM cashes WHERE deleted_at IS NULL
UNION ALL SELECT 'discount', COUNT(discount), SUM(discount <> 0) FROM cashes WHERE deleted_at IS NULL;
-- جمع کل هر ستونی که مقدار دارد → مبنای تطبیق برای ابزار
SELECT
CAST(SUM(input) AS CHAR) AS sum_input,
CAST(SUM(output) AS CHAR) AS sum_output,
CAST(SUM(value) AS CHAR) AS sum_value,
CAST(SUM(original_value) AS CHAR) AS sum_original_value,
CAST(SUM(rial_input) AS CHAR) AS sum_rial_input,
CAST(SUM(rial_output) AS CHAR) AS sum_rial_output,
CAST(SUM(price) AS CHAR) AS sum_price
FROM cashes WHERE deleted_at IS NULL;
-- به تفکیک نوع سند: کدام نوع از کدام ستون استفاده می‌کند؟
-- (type: 9=سفارش 1=آب‌شده 2=حواله 3=چک 4=پولی)
SELECT type AS cash_type,
COUNT(*) AS n,
SUM(input IS NOT NULL AND input <> 0) AS has_input,
SUM(output IS NOT NULL AND output <> 0) AS has_output,
SUM(value IS NOT NULL AND value <> 0) AS has_value,
SUM(rial_input IS NOT NULL AND rial_input <> 0) AS has_rial_in,
SUM(rial_output IS NOT NULL AND rial_output <> 0) AS has_rial_out,
SUM(price IS NOT NULL AND price <> 0) AS has_price
FROM cashes WHERE deleted_at IS NULL
GROUP BY type ORDER BY type;
-- آیا اصلاً ردیفی هست که هیچ مبلغی نداشته باشد؟
SELECT 'rows_with_no_amount_at_all' AS metric, COUNT(*) AS n
FROM cashes WHERE deleted_at IS NULL
AND COALESCE(input,0)=0 AND COALESCE(output,0)=0
AND COALESCE(value,0)=0 AND COALESCE(rial_input,0)=0
AND COALESCE(rial_output,0)=0 AND COALESCE(price,0)=0;
-- ---------------------------------------------------------------------------
-- 🔴 سؤال ۲ — موبایل تکراری: آیا قاعده‌ی «مسئول فروش برنده» کافی است؟
--
-- ۲۷ گروه تکراری وجود دارد. اگر در یک گروه هر دو ردیف مشتری عادی باشند
-- (type != 1)، آن قاعده جواب نمی‌دهد و قاعده‌ی پشتیبان لازم است.
-- ---------------------------------------------------------------------------
SELECT '=== 2. DUPLICATE MOBILE — is the "sales expert wins" rule enough? ===' AS section;
-- در هر گروه تکراری، چند ردیف type=1 (کارشناس) هست؟
-- experts_in_group = 1 → قاعده جواب می‌دهد
-- experts_in_group = 0 → هیچ کارشناسی نیست، قاعده بی‌اثر → پشتیبان لازم
-- experts_in_group > 1 → چند کارشناس با یک شماره، قاعده مبهم
SELECT experts_in_group, COUNT(*) AS n_groups, SUM(rows_in_group) AS n_rows
FROM (
SELECT mobile,
COUNT(*) AS rows_in_group,
SUM(type = 1) AS experts_in_group
FROM customers
WHERE deleted_at IS NULL AND mobile IS NOT NULL AND mobile <> ''
GROUP BY mobile HAVING COUNT(*) > 1
) g
GROUP BY experts_in_group ORDER BY experts_in_group;
-- آیا ردیف‌های تکراری updated_at متفاوت دارند؟ (قاعده‌ی پشتیبان پیشنهادی)
-- اگر n_ties > 0 یعنی updated_at هم تفکیک نمی‌کند
SELECT 'groups_where_updated_at_ties' AS metric, COUNT(*) AS n
FROM (
SELECT mobile, COUNT(*) AS c, COUNT(DISTINCT updated_at) AS d
FROM customers
WHERE deleted_at IS NULL AND mobile IS NOT NULL AND mobile <> ''
GROUP BY mobile HAVING COUNT(*) > 1 AND COUNT(DISTINCT updated_at) < COUNT(*)
) t;
-- آیا ردیف‌های تکراری بدهی دارند؟ ادغامشان یعنی جمع‌کردن بدهی
SELECT 'dup_groups_with_debt' AS metric, COUNT(*) AS n
FROM (
SELECT mobile FROM customers
WHERE deleted_at IS NULL AND mobile IS NOT NULL AND mobile <> ''
GROUP BY mobile
HAVING COUNT(*) > 1 AND (SUM(COALESCE(remain,0)) <> 0 OR SUM(COALESCE(rial_remain,0)) <> 0)
) t;
-- آیا ردیف‌های تکراری سفارش دارند؟
SELECT 'dup_rows_with_orders' AS metric, COUNT(DISTINCT c.id) AS n
FROM customers c
JOIN orders o ON o.customer_id = c.id AND o.deleted_at IS NULL
WHERE c.deleted_at IS NULL AND c.mobile IN (
SELECT mobile FROM customers
WHERE deleted_at IS NULL AND mobile IS NOT NULL AND mobile <> ''
GROUP BY mobile HAVING COUNT(*) > 1
);
-- ---------------------------------------------------------------------------
-- سؤال ۳ — نگاشت تصویر محصول: سه ستون → چهار نقش ProductImageRole
--
-- مرجع: §۹ — file_id / mobile_pic_id / indicator_id_id
-- ---------------------------------------------------------------------------
SELECT '=== 3. PRODUCT IMAGE ROLES ===' AS section;
SELECT 'file_id (FEATURED?)' AS col, COUNT(file_id) AS not_null FROM product WHERE deleted_at IS NULL
UNION ALL SELECT 'mobile_pic_id (FEATURED_MOBILE?)', COUNT(mobile_pic_id) FROM product WHERE deleted_at IS NULL
UNION ALL SELECT 'indicator_id_id (?)', COUNT(indicator_id_id) FROM product WHERE deleted_at IS NULL;
-- products_productimage همان GALLERY است؟ چند تصویر per محصول؟
SELECT 'gallery_rows' AS metric, COUNT(*) AS n FROM products_productimage WHERE deleted_at IS NULL
UNION ALL SELECT 'gallery_distinct_products', COUNT(DISTINCT product_id) FROM products_productimage WHERE deleted_at IS NULL
UNION ALL SELECT 'gallery_orphan_image', SUM(i.id IS NULL)
FROM products_productimage pi LEFT JOIN image i ON i.id = pi.image_id WHERE pi.deleted_at IS NULL
UNION ALL SELECT 'gallery_orphan_product', SUM(p.id IS NULL)
FROM products_productimage pi LEFT JOIN product p ON p.id = pi.product_id WHERE pi.deleted_at IS NULL;
-- ستون w در products_productimage — آیا نقش را تفکیک می‌کند؟
SELECT 'prod_image.w' AS col, COALESCE(w,'(null)') AS val, COUNT(*) AS n
FROM products_productimage WHERE deleted_at IS NULL GROUP BY w ORDER BY n DESC LIMIT 10;
-- یتیم‌های تصویر محصول (file_id → image)
SELECT 'product.file_id orphan' AS ref, COUNT(*) AS orphans
FROM product p LEFT JOIN image i ON i.id = p.file_id
WHERE p.deleted_at IS NULL AND p.file_id IS NOT NULL AND i.id IS NULL
UNION ALL
SELECT 'product.mobile_pic_id orphan', COUNT(*)
FROM product p LEFT JOIN image i ON i.id = p.mobile_pic_id
WHERE p.deleted_at IS NULL AND p.mobile_pic_id IS NOT NULL AND i.id IS NULL;
-- ---------------------------------------------------------------------------
-- سؤال ۴ — کارشناس فروش (type=1): ۵۶ ردیف که به AdminUser می‌روند
-- مرجع: §۵.۷ · D17
-- ---------------------------------------------------------------------------
SELECT '=== 4. SALES EXPERTS (type=1 -> AdminUser) ===' AS section;
SELECT 'experts_total' AS metric, COUNT(*) AS n FROM customers WHERE deleted_at IS NULL AND type = 1
UNION ALL SELECT 'experts_with_password', SUM(password IS NOT NULL AND password <> '') FROM customers WHERE deleted_at IS NULL AND type = 1
UNION ALL SELECT 'experts_with_ncode', SUM(ncode IS NOT NULL AND ncode <> '') FROM customers WHERE deleted_at IS NULL AND type = 1
UNION ALL SELECT 'experts_with_city', SUM(city_id IS NOT NULL) FROM customers WHERE deleted_at IS NULL AND type = 1
UNION ALL SELECT 'experts_with_percent', SUM(percent IS NOT NULL AND percent <> 0) FROM customers WHERE deleted_at IS NULL AND type = 1
UNION ALL SELECT 'experts_referenced_as_reagent', COUNT(DISTINCT reagent_id) FROM customers WHERE deleted_at IS NULL AND reagent_id IS NOT NULL;
-- 🔴 حیاتی: آیا reagent_id واقعاً به customers اشاره می‌کند؟ (§۵.۷)
-- اگر orphan_in_customers صفر یا کم باشد → تأیید می‌شود
SELECT 'reagent_id orphan vs customers' AS ref, COUNT(*) AS orphans
FROM customers c LEFT JOIN customers r ON r.id = c.reagent_id
WHERE c.deleted_at IS NULL AND c.reagent_id IS NOT NULL AND r.id IS NULL;
-- آیا همه‌ی reagent_id ها به ردیف type=1 اشاره می‌کنند؟
SELECT 'reagent points to non-expert' AS ref, COUNT(*) AS n
FROM customers c JOIN customers r ON r.id = c.reagent_id
WHERE c.deleted_at IS NULL AND r.type <> 1;
SELECT '=== END ===' AS section;