Загрузка данных


BEGIN READ ONLY;

SET LOCAL statement_timeout = '180s';

WITH
latest_death_info AS MATERIALIZED (
    SELECT DISTINCT ON (a.individual_id)
           a.individual_id,
           a.death_date
    FROM ourpension.application_death_info a
    WHERE a.accepted IS NOT NULL
      AND a.canceled IS NULL
      AND a.rejected IS NULL
    ORDER BY a.individual_id, a.version DESC
),

-- Общая контрольная выборка до исключения переводов.
sample_sharers AS MATERIALIZED (
    SELECT s.id
    FROM latest_death_info di
    JOIN ourpension.sharer s
      ON s.individual_id = di.individual_id
    JOIN ourpension.contract c
      ON c.id = s.contract_id
    WHERE c.service_type = 'OPS'
      AND EXISTS (
          SELECT 1
          FROM report.dia_param p
          WHERE di.death_date <= p.report_date
      )
    ORDER BY di.individual_id, s.id
    LIMIT 200
),

-- Отбор участников по исходной схеме.
old_ops_sharer AS MATERIALIZED (
    SELECT s.id,
           di.death_date
    FROM sample_sharers sample
    JOIN ourpension.sharer s
      ON s.id = sample.id
    JOIN ourpension.contract c
      ON c.id = s.contract_id
    JOIN report.dia_param p
      ON true
    JOIN LATERAL (
        SELECT a.death_date
        FROM ourpension.application_death_info a
        WHERE a.individual_id = s.individual_id
          AND a.accepted IS NOT NULL
          AND a.canceled IS NULL
          AND a.rejected IS NULL
        ORDER BY a.version DESC
        LIMIT 1
    ) di ON true
    LEFT JOIN LATERAL (
        SELECT d.sharer_id
        FROM back_office.ops_transfer_details d
        JOIN back_office.ops_transfer_register tr
          ON tr.id = d.ops_transfer_register_id
        JOIN back_office.operation o
          ON o.ops_transfer_register_id = tr.id
        WHERE d.sharer_id = s.id
          AND o.approved IS NOT NULL
          AND o.effective_date <= p.report_date
        LIMIT 1
    ) transfer ON true
    WHERE c.service_type = 'OPS'
      AND di.death_date <= p.report_date
      AND transfer.sharer_id IS NULL
),

-- Отбор участников по новой схеме.
new_ops_sharer AS MATERIALIZED (
    SELECT s.id,
           di.death_date
    FROM latest_death_info di
    JOIN report.dia_param p
      ON di.death_date <= p.report_date
    JOIN ourpension.sharer s
      ON s.individual_id = di.individual_id
    JOIN sample_sharers sample
      ON sample.id = s.id
    JOIN ourpension.contract c
      ON c.id = s.contract_id
    WHERE c.service_type = 'OPS'
      AND NOT EXISTS (
          SELECT 1
          FROM back_office.ops_transfer_details d
          JOIN back_office.ops_transfer_register tr
            ON tr.id = d.ops_transfer_register_id
          JOIN back_office.operation o
            ON o.ops_transfer_register_id = tr.id
          WHERE d.sharer_id = s.id
            AND o.approved IS NOT NULL
            AND o.effective_date <= p.report_date
      )
),

categories(mnemonics, category) AS (
    VALUES
        ('ОПС',             'ops'),
        ('ОПС ГВ',          'ops'),
        ('ОПС КП',          'ops'),
        ('Р ПП ОПС',        'ops'),
        ('ОПС ИД',          'ops_id'),
        ('ОПС ФР',          'ops_id'),
        ('Р ПП ОПС ИД',     'ops_id'),
        ('ДПС Л',           'dps_l'),
        ('ДПС Л ГВ',        'dps_l'),
        ('ДПС Л КП',        'dps_l'),
        ('Р ПП ДПС Л',      'dps_l'),
        ('ДПС Л ИД',        'dps_l_id'),
        ('ДПС Л ФР',        'dps_l_id'),
        ('Р ПП ДПС Л ИД',   'dps_l_id'),
        ('ДПС Г',           'dps_g'),
        ('ДПС Г ГВ',        'dps_g'),
        ('ДПС Г КП',        'dps_g'),
        ('Р ПП ДПС Г',      'dps_g'),
        ('ДПС Г ИД',        'dps_g_id'),
        ('ДПС Г ФР',        'dps_g_id'),
        ('Р ПП ДПС Г ИД',   'dps_g_id'),
        ('ДПС МК',          'dps_mk'),
        ('ДПС МК ГВ',       'dps_mk'),
        ('ДПС МК КП',       'dps_mk'),
        ('Р ПП ДПС МК',     'dps_mk'),
        ('ДПС МК ИД',       'dps_mk_id'),
        ('ДПС МК ФР',       'dps_mk_id'),
        ('Р ПП ДПС МК ИД',  'dps_mk_id')
),

-- Исходные соединения: от счёта участника к проводкам.
-- Агрегация вынесена ниже, чтобы сравнивать обе версии одинаково.
old_movements AS (
    SELECT s.id AS sharer_id,
           category.category,
           t.value AS signed_value
    FROM old_ops_sharer s
    JOIN back_office.account da
      ON da.owner_sharer_id = s.id
    JOIN back_office.account_type dat
      ON dat.id = da.account_type_id
    JOIN categories category
      ON category.mnemonics = dat.mnemonics
    JOIN back_office.transaction t
      ON t.debit_account_id = da.id
    JOIN back_office.account ca
      ON ca.id = t.credit_account_id
    JOIN back_office.account_type cat
      ON cat.id = ca.account_type_id
    WHERE cat.mnemonics IN ('Р ОПС', 'Р ОПС ИД')

    UNION ALL

    SELECT s.id AS sharer_id,
           category.category,
           -t.value AS signed_value
    FROM old_ops_sharer s
    JOIN back_office.account ca
      ON ca.owner_sharer_id = s.id
    JOIN back_office.account_type cat
      ON cat.id = ca.account_type_id
    JOIN categories category
      ON category.mnemonics = cat.mnemonics
    JOIN back_office.transaction t
      ON t.credit_account_id = ca.id
    JOIN back_office.account da
      ON da.id = t.debit_account_id
    JOIN back_office.account_type dat
      ON dat.id = da.account_type_id
    WHERE dat.mnemonics IN ('Р ОПС', 'Р ОПС ИД')
),

reserve_accounts AS MATERIALIZED (
    SELECT array_agg(a.id) AS ids
    FROM back_office.account a
    JOIN back_office.account_type at
      ON at.id = a.account_type_id
    WHERE at.mnemonics IN ('Р ОПС', 'Р ОПС ИД')
),

reserve_movements AS NOT MATERIALIZED (
    SELECT t.debit_account_id AS account_id,
           t.value AS signed_value
    FROM reserve_accounts r
    JOIN back_office.transaction t
      ON t.credit_account_id = ANY (r.ids)

    UNION ALL

    SELECT t.credit_account_id AS account_id,
           -t.value AS signed_value
    FROM reserve_accounts r
    JOIN back_office.transaction t
      ON t.debit_account_id = ANY (r.ids)
),

-- Новые соединения: от резервных счетов к счетам участников.
new_movements AS (
    SELECT s.id AS sharer_id,
           category.category,
           m.signed_value
    FROM reserve_movements m
    JOIN back_office.account a
      ON a.id = m.account_id
    JOIN back_office.account_type at
      ON at.id = a.account_type_id
    JOIN categories category
      ON category.mnemonics = at.mnemonics
    JOIN new_ops_sharer s
      ON s.id = a.owner_sharer_id
),

both_movements AS (
    SELECT 'old' AS source, m.*
    FROM old_movements m

    UNION ALL

    SELECT 'new' AS source, m.*
    FROM new_movements m
),

balances AS MATERIALIZED (
    SELECT source,
           sharer_id,
           SUM(CASE WHEN category = 'ops'
                    THEN signed_value ELSE 0 END) AS ops,
           SUM(CASE WHEN category = 'ops_id'
                    THEN signed_value ELSE 0 END) AS ops_id,
           SUM(CASE WHEN category = 'dps_l'
                    THEN signed_value ELSE 0 END) AS dps_l,
           SUM(CASE WHEN category = 'dps_l_id'
                    THEN signed_value ELSE 0 END) AS dps_l_id,
           SUM(CASE WHEN category = 'dps_g'
                    THEN signed_value ELSE 0 END) AS dps_g,
           SUM(CASE WHEN category = 'dps_g_id'
                    THEN signed_value ELSE 0 END) AS dps_g_id,
           SUM(CASE WHEN category = 'dps_mk'
                    THEN signed_value ELSE 0 END) AS dps_mk,
           SUM(CASE WHEN category = 'dps_mk_id'
                    THEN signed_value ELSE 0 END) AS dps_mk_id,
           SUM(signed_value) AS total
    FROM both_movements
    GROUP BY source, sharer_id
    HAVING SUM(signed_value) <> 0
),

-- Учитываем финальные соединения исходного отчёта.
results AS MATERIALIZED (
    SELECT b.*,
           i.insurance_number,
           s.number AS sharer_number,
           di.death_date
    FROM balances b
    JOIN ourpension.sharer s
      ON s.id = b.sharer_id
    JOIN ourpension.individual i
      ON i.id = s.individual_id
    JOIN LATERAL (
        SELECT a.death_date
        FROM ourpension.application_death_info a
        WHERE a.individual_id = s.individual_id
          AND a.accepted IS NOT NULL
          AND a.canceled IS NULL
          AND a.rejected IS NULL
        ORDER BY a.version DESC
        LIMIT 1
    ) di ON true
),

old_only_selection AS (
    SELECT id, death_date FROM old_ops_sharer
    EXCEPT ALL
    SELECT id, death_date FROM new_ops_sharer
),

new_only_selection AS (
    SELECT id, death_date FROM new_ops_sharer
    EXCEPT ALL
    SELECT id, death_date FROM old_ops_sharer
),

old_only_results AS (
    SELECT to_jsonb(r) - 'source' AS row_data
    FROM results r
    WHERE source = 'old'

    EXCEPT ALL

    SELECT to_jsonb(r) - 'source'
    FROM results r
    WHERE source = 'new'
),

new_only_results AS (
    SELECT to_jsonb(r) - 'source' AS row_data
    FROM results r
    WHERE source = 'new'

    EXCEPT ALL

    SELECT to_jsonb(r) - 'source'
    FROM results r
    WHERE source = 'old'
)

SELECT
    (SELECT COUNT(*) FROM sample_sharers)
        AS sample_count,
    (SELECT COUNT(*) FROM old_ops_sharer)
        AS old_selected_count,
    (SELECT COUNT(*) FROM new_ops_sharer)
        AS new_selected_count,
    (SELECT COUNT(*) FROM old_only_selection)
        AS selection_only_old,
    (SELECT COUNT(*) FROM new_only_selection)
        AS selection_only_new,
    (SELECT COUNT(*) FROM results WHERE source = 'old')
        AS old_result_count,
    (SELECT COUNT(*) FROM results WHERE source = 'new')
        AS new_result_count,
    (SELECT COUNT(*) FROM old_only_results)
        AS result_only_old,
    (SELECT COUNT(*) FROM new_only_results)
        AS result_only_new,
    (SELECT jsonb_agg(x.row_data)
     FROM (SELECT row_data FROM old_only_results LIMIT 5) x)
        AS differences_old_examples,
    (SELECT jsonb_agg(x.row_data)
     FROM (SELECT row_data FROM new_only_results LIMIT 5) x)
        AS differences_new_examples;

ROLLBACK;