analytics/mag_pbi/scripts/migrate_to_manufacturers_structure.sql
2026-02-18 14:36:38 +03:00

253 lines
15 KiB
Transact-SQL
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

-- =============================================================================
-- Миграция: логистика, дни продаж и этапы оплаты — на manufacturers
-- manufacturer_counterparty_map — только связь manufacturer_id + contractor_1c_id (из 1С)
--
-- ВАЖНО: Перед запуском выполнить migrate_map_to_contractor_1c.sql
-- (удаление counterparties, переход на contractor_1c_id)
--
-- ИСТОЧНИК: contractor_producer_mapping, contractor_producer_payment_stage
-- (сопоставление по v_contractors, v_producers → counterparties, manufacturers)
--
-- 1. manufacturers: добавить days_of_sales, logistics_days, roic_norm
-- 2. manufacturer_payment_stage: новая таблица, FK на manufacturers
-- 3. Миграция из contractor_producer_* в manufacturers, map, manufacturer_payment_stage
-- 4. manufacturer_counterparty_map: убрать days_of_sales, logistics_days, roic_norm (если есть)
-- 5. Удалить contractor_producer_*, manufacturer_counterparty_payment_stage
-- =============================================================================
USE [mag_pbi]
GO
SET NOCOUNT ON;
-- =============================================================================
-- 1. manufacturers: добавить days_of_sales, logistics_days, roic_norm
-- =============================================================================
IF NOT EXISTS (SELECT 1 FROM sys.columns WHERE object_id = OBJECT_ID(N'[analytics].[manufacturers]') AND name = 'days_of_sales')
ALTER TABLE [analytics].[manufacturers] ADD [days_of_sales] INT NOT NULL DEFAULT 180;
IF NOT EXISTS (SELECT 1 FROM sys.columns WHERE object_id = OBJECT_ID(N'[analytics].[manufacturers]') AND name = 'logistics_days')
ALTER TABLE [analytics].[manufacturers] ADD [logistics_days] INT NOT NULL DEFAULT 120;
IF NOT EXISTS (SELECT 1 FROM sys.columns WHERE object_id = OBJECT_ID(N'[analytics].[manufacturers]') AND name = 'roic_norm')
ALTER TABLE [analytics].[manufacturers] ADD [roic_norm] DECIMAL(12,4) NULL;
-- Миграция из manufacturers.ROI_norm (если ещё не удалена, roic_norm уже добавлена)
IF EXISTS (SELECT 1 FROM sys.columns WHERE object_id = OBJECT_ID(N'[analytics].[manufacturers]') AND name = 'ROI_norm')
AND EXISTS (SELECT 1 FROM sys.columns WHERE object_id = OBJECT_ID(N'[analytics].[manufacturers]') AND name = 'roic_norm')
BEGIN
UPDATE [analytics].[manufacturers] SET [roic_norm] = [ROI_norm] WHERE [roic_norm] IS NULL AND [ROI_norm] IS NOT NULL;
END
-- Удалить старые поля manufacturers (n_percent, n_days, m_percent, m_days, ROI_norm)
IF EXISTS (SELECT 1 FROM sys.columns WHERE object_id = OBJECT_ID(N'[analytics].[manufacturers]') AND name = 'ROI_norm')
ALTER TABLE [analytics].[manufacturers] DROP COLUMN [ROI_norm];
IF EXISTS (SELECT 1 FROM sys.columns WHERE object_id = OBJECT_ID(N'[analytics].[manufacturers]') AND name = 'n_percent')
ALTER TABLE [analytics].[manufacturers] DROP COLUMN [n_percent];
IF EXISTS (SELECT 1 FROM sys.columns WHERE object_id = OBJECT_ID(N'[analytics].[manufacturers]') AND name = 'n_days')
ALTER TABLE [analytics].[manufacturers] DROP COLUMN [n_days];
IF EXISTS (SELECT 1 FROM sys.columns WHERE object_id = OBJECT_ID(N'[analytics].[manufacturers]') AND name = 'm_percent')
ALTER TABLE [analytics].[manufacturers] DROP COLUMN [m_percent];
IF EXISTS (SELECT 1 FROM sys.columns WHERE object_id = OBJECT_ID(N'[analytics].[manufacturers]') AND name = 'm_days')
ALTER TABLE [analytics].[manufacturers] DROP COLUMN [m_days];
PRINT 'manufacturers: добавлены days_of_sales, logistics_days, roic_norm';
GO
-- =============================================================================
-- 2. manufacturer_payment_stage — этапы оплаты, привязаны к manufacturers
-- =============================================================================
IF OBJECT_ID(N'[analytics].[manufacturer_payment_stage]', N'U') IS NULL
BEGIN
CREATE TABLE [analytics].[manufacturer_payment_stage] (
[id] INT IDENTITY(1,1) NOT NULL,
[manufacturer_id] INT NOT NULL,
[name] NVARCHAR(255) NOT NULL,
[days] INT NOT NULL,
[percent] DECIMAL(9,4) NOT NULL,
[sort_order] INT NOT NULL DEFAULT 0,
CONSTRAINT [PK_manufacturer_payment_stage] PRIMARY KEY CLUSTERED ([id]),
CONSTRAINT [FK_manufacturer_payment_stage] FOREIGN KEY ([manufacturer_id])
REFERENCES [analytics].[manufacturers]([id]) ON DELETE CASCADE
);
CREATE NONCLUSTERED INDEX [IX_manufacturer_payment_stage_manufacturer_id]
ON [analytics].[manufacturer_payment_stage]([manufacturer_id]);
PRINT 'Создана таблица manufacturer_payment_stage';
END
GO
-- =============================================================================
-- Миграция из contractor_producer_mapping и contractor_producer_payment_stage
-- (требует v_contractors, v_producers; manufacturer_counterparty_map с contractor_1c_id)
-- =============================================================================
IF OBJECT_ID(N'[analytics].[contractor_producer_mapping]', N'U') IS NOT NULL
AND OBJECT_ID(N'[analytics].[contractor_producer_payment_stage]', N'U') IS NOT NULL
AND OBJECT_ID(N'[analytics].[v_contractors]', N'V') IS NOT NULL
AND OBJECT_ID(N'[analytics].[v_producers]', N'V') IS NOT NULL
AND EXISTS (SELECT 1 FROM sys.columns WHERE object_id = OBJECT_ID(N'[analytics].[manufacturer_counterparty_map]') AND name = 'contractor_1c_id')
BEGIN
-- 3a. Добавить недостающие manufacturers (по именам из 1С)
INSERT INTO [analytics].[manufacturers] (manufacturer, days_of_sales, logistics_days, roic_norm)
SELECT t.producer_name, t.days_of_sales, t.logistics_days, t.roic_norm
FROM (
SELECT LTRIM(RTRIM(p.producer_name)) AS producer_name, m.days_of_sales, m.logistics_days, m.roic_norm,
ROW_NUMBER() OVER (PARTITION BY LTRIM(RTRIM(p.producer_name)) ORDER BY m.id) AS rn
FROM [analytics].[contractor_producer_mapping] m
JOIN [analytics].[v_producers] p ON p.producer_1c_id = m.producer_1c_id
) t
WHERE t.rn = 1
AND NOT EXISTS (SELECT 1 FROM [analytics].[manufacturers] man WHERE LTRIM(RTRIM(man.manufacturer)) = t.producer_name);
-- 3b. Обновить manufacturers (days, logistics, roic) из contractor_producer_mapping
UPDATE man
SET man.days_of_sales = src.days_of_sales,
man.logistics_days = src.logistics_days,
man.roic_norm = COALESCE(man.roic_norm, src.roic_norm)
FROM [analytics].[manufacturers] man
JOIN (
SELECT p.producer_name, m.days_of_sales, m.logistics_days, m.roic_norm,
ROW_NUMBER() OVER (PARTITION BY LTRIM(RTRIM(p.producer_name)) ORDER BY m.id) AS rn
FROM [analytics].[contractor_producer_mapping] m
JOIN [analytics].[v_producers] p ON p.producer_1c_id = m.producer_1c_id
) src ON LTRIM(RTRIM(man.manufacturer)) = LTRIM(RTRIM(src.producer_name)) AND src.rn = 1;
-- 3c. Вставить связи в manufacturer_counterparty_map (contractor_1c_id из 1С)
INSERT INTO [analytics].[manufacturer_counterparty_map] (manufacturer_id, contractor_1c_id)
SELECT man.id, m.contractor_1c_id
FROM [analytics].[contractor_producer_mapping] m
JOIN [analytics].[v_producers] p ON p.producer_1c_id = m.producer_1c_id
JOIN [analytics].[manufacturers] man ON LTRIM(RTRIM(man.manufacturer)) = LTRIM(RTRIM(p.producer_name))
WHERE NOT EXISTS (
SELECT 1 FROM [analytics].[manufacturer_counterparty_map] mcm
WHERE mcm.manufacturer_id = man.id AND mcm.contractor_1c_id = m.contractor_1c_id
);
PRINT 'Миграция из contractor_producer_mapping: вставлено связей ' + CAST(@@ROWCOUNT AS NVARCHAR(10));
-- 3d. Миграция этапов в manufacturer_payment_stage (по одному набору на производителя — из первого mapping)
INSERT INTO [analytics].[manufacturer_payment_stage] (manufacturer_id, name, [days], [percent], sort_order)
SELECT man.id, s.name, s.[days], s.[percent], s.sort_order
FROM [analytics].[contractor_producer_payment_stage] s
JOIN [analytics].[contractor_producer_mapping] m ON m.id = s.mapping_id
JOIN [analytics].[v_producers] p ON p.producer_1c_id = m.producer_1c_id
JOIN [analytics].[manufacturers] man ON LTRIM(RTRIM(man.manufacturer)) = LTRIM(RTRIM(p.producer_name))
WHERE m.id = (
SELECT MIN(m2.id) FROM [analytics].[contractor_producer_mapping] m2
JOIN [analytics].[v_producers] p2 ON p2.producer_1c_id = m2.producer_1c_id
WHERE LTRIM(RTRIM(p2.producer_name)) = LTRIM(RTRIM(p.producer_name))
)
AND man.id NOT IN (SELECT manufacturer_id FROM [analytics].[manufacturer_payment_stage]);
PRINT 'Миграция из contractor_producer_payment_stage: вставлено этапов ' + CAST(@@ROWCOUNT AS NVARCHAR(10));
END
GO
-- Fallback: миграция из manufacturer_counterparty_payment_stage (если contractor_producer уже удалён)
IF OBJECT_ID(N'[analytics].[manufacturer_counterparty_payment_stage]', N'U') IS NOT NULL
BEGIN
INSERT INTO [analytics].[manufacturer_payment_stage] (manufacturer_id, name, [days], [percent], sort_order)
SELECT mcm.manufacturer_id, s.name, s.[days], s.[percent], s.sort_order
FROM [analytics].[manufacturer_counterparty_payment_stage] s
JOIN [analytics].[manufacturer_counterparty_map] mcm ON mcm.id = s.map_id
WHERE mcm.id = (SELECT MIN(m2.id) FROM [analytics].[manufacturer_counterparty_map] m2 WHERE m2.manufacturer_id = mcm.manufacturer_id)
AND mcm.manufacturer_id NOT IN (SELECT manufacturer_id FROM [analytics].[manufacturer_payment_stage]);
PRINT 'Миграция из manufacturer_counterparty_payment_stage: ' + CAST(@@ROWCOUNT AS NVARCHAR(10));
END
GO
-- Дефолтные этапы для manufacturers без этапов (из старых n_/m_ полей, если остались — уже удалены)
-- Берём manufacturers без этапов и добавляем Предоплата+Постоплата
INSERT INTO [analytics].[manufacturer_payment_stage] (manufacturer_id, name, [days], [percent], sort_order)
SELECT man.id, N'Предоплата', 7, 50, 0
FROM [analytics].[manufacturers] man
WHERE NOT EXISTS (SELECT 1 FROM [analytics].[manufacturer_payment_stage] s WHERE s.manufacturer_id = man.id);
INSERT INTO [analytics].[manufacturer_payment_stage] (manufacturer_id, name, [days], [percent], sort_order)
SELECT man.id, N'Постоплата', 120, 50, 1
FROM [analytics].[manufacturers] man
WHERE (SELECT COUNT(*) FROM [analytics].[manufacturer_payment_stage] s WHERE s.manufacturer_id = man.id) = 1;
PRINT 'Созданы дефолтные этапы оплаты';
GO
-- =============================================================================
-- 3. manufacturer_counterparty_map: убрать days_of_sales, logistics_days, roic_norm
-- =============================================================================
IF EXISTS (SELECT 1 FROM sys.columns WHERE object_id = OBJECT_ID(N'[analytics].[manufacturer_counterparty_map]') AND name = 'days_of_sales')
ALTER TABLE [analytics].[manufacturer_counterparty_map] DROP COLUMN [days_of_sales];
IF EXISTS (SELECT 1 FROM sys.columns WHERE object_id = OBJECT_ID(N'[analytics].[manufacturer_counterparty_map]') AND name = 'logistics_days')
ALTER TABLE [analytics].[manufacturer_counterparty_map] DROP COLUMN [logistics_days];
IF EXISTS (SELECT 1 FROM sys.columns WHERE object_id = OBJECT_ID(N'[analytics].[manufacturer_counterparty_map]') AND name = 'roic_norm')
ALTER TABLE [analytics].[manufacturer_counterparty_map] DROP COLUMN [roic_norm];
PRINT 'manufacturer_counterparty_map: оставлены только manufacturer_id, counterparty_id';
GO
-- =============================================================================
-- 4. Удалить manufacturer_counterparty_payment_stage и contractor_producer_*
-- =============================================================================
IF OBJECT_ID(N'[analytics].[manufacturer_counterparty_payment_stage]', N'U') IS NOT NULL
DROP TABLE [analytics].[manufacturer_counterparty_payment_stage];
IF OBJECT_ID(N'[analytics].[v_contractor_producer_mapping]', N'V') IS NOT NULL
DROP VIEW [analytics].[v_contractor_producer_mapping];
IF OBJECT_ID(N'[analytics].[contractor_producer_payment_stage]', N'U') IS NOT NULL
DROP TABLE [analytics].[contractor_producer_payment_stage];
IF OBJECT_ID(N'[analytics].[contractor_producer_mapping]', N'U') IS NOT NULL
DROP TABLE [analytics].[contractor_producer_mapping];
PRINT 'Удалены manufacturer_counterparty_payment_stage и contractor_producer_*';
GO
-- =============================================================================
-- 5. Представление для API (map + manufacturer + counterparty, roic из manufacturers)
-- =============================================================================
IF OBJECT_ID(N'[analytics].[v_manufacturer_counterparty_mapping]', N'V') IS NOT NULL
DROP VIEW [analytics].[v_manufacturer_counterparty_mapping];
GO
CREATE VIEW [analytics].[v_manufacturer_counterparty_mapping] AS
SELECT
mcm.id,
mcm.manufacturer_id,
p.producer_id,
man.manufacturer AS manufacturer_name,
mcm.contractor_1c_id,
c.contractor_id,
c.contractor_name AS contractor_name,
man.days_of_sales,
man.logistics_days,
man.roic_norm
FROM [analytics].[manufacturer_counterparty_map] mcm
LEFT JOIN [analytics].[manufacturers] man ON man.id = mcm.manufacturer_id
LEFT JOIN [analytics].[v_contractors] c ON c.contractor_1c_id = mcm.contractor_1c_id
LEFT JOIN [analytics].[v_producers] p ON LTRIM(RTRIM(p.producer_name)) = LTRIM(RTRIM(man.manufacturer));
GO
PRINT 'Создано представление v_manufacturer_counterparty_mapping';
GO
-- =============================================================================
-- 6. View для обратной совместимости процедур (manufacturer + roic + n_/m_)
-- =============================================================================
IF OBJECT_ID(N'[analytics].[v_manufacturers_roi_compat]', N'V') IS NOT NULL
DROP VIEW [analytics].[v_manufacturers_roi_compat];
GO
CREATE VIEW [analytics].[v_manufacturers_roi_compat] AS
SELECT
man.id,
man.manufacturer,
man.roic_norm AS ROI_norm,
n_stage.[percent] / 100.0 AS n_percent,
n_stage.[days] AS n_days,
m_stage.[percent] / 100.0 AS m_percent,
m_stage.[days] AS m_days
FROM [analytics].[manufacturers] man
LEFT JOIN (
SELECT manufacturer_id, [percent], [days],
ROW_NUMBER() OVER (PARTITION BY manufacturer_id ORDER BY sort_order, [days]) AS rn
FROM [analytics].[manufacturer_payment_stage]
) n_stage ON n_stage.manufacturer_id = man.id AND n_stage.rn = 1
LEFT JOIN (
SELECT manufacturer_id, [percent], [days],
ROW_NUMBER() OVER (PARTITION BY manufacturer_id ORDER BY sort_order, [days]) AS rn
FROM [analytics].[manufacturer_payment_stage]
) m_stage ON m_stage.manufacturer_id = man.id AND m_stage.rn = 2;
GO