Я надеюсь, что кто-нибудь может помочь мне решить эту проблему наилучшим образом.
В настоящее время наша организация использует циклы продаж для оценки эффективности наших ритейлеров по дате их первой отгрузки. Вот бизнес-правила:
Nurture Stage - 1st year
Graduate Stage - 2nd year
Ongoing Stage - 3rd year and on
Inactive Stage - stop doing business
Restart Stage - do business with us after an Inactive Stage
Change Owner Stage - sell their business and new owner does business with us
Чтобы усложнить этот беспорядок, ни один продавец не может быть в программе того же типа в любой момент времени. Поэтому, если они покупают готовый продукт у нас, они также не могут участвовать в Программе, где они покупают материалы для его самостоятельного изготовления.
StageNo ProgramNo CustomerNo ProgramType StageDescription StartDate EndDate
CAPS041835 CAP010611 RL023238 Packaged Nurture 2019-04-04 2019-04-04
CAPS041836 CAP010611 RL023238 Packaged Inactive 2019-04-05 2999-01-01
CAPS041837 CAP010612 RL023238 Pre-Made in Bulk Nurture 2019-04-04 2999-01-01
Выше приведен пример аномалии в данных. 01.01.2999 просто означает, что в нашей ERP это пустая дата.
04/04/2019 пользователь создал упакованную программу и решил, что розничный продавец должен был настроить Pre-Made in Bulk вместо Packaged.
ERP заканчивает текущую стадию в последнюю дату Счета, и, если она не существует, завершит ее с сегодняшней датой и запустит Неактивную Стаду с Сегодня + 1.
Итак, если я запустил аналитику, любые поставки 04.04.199 будут применяться как к Пакетным, так и к Готовым программам.
В идеале, я ХОЧУ полностью избавиться от упакованной программы, но если это невозможно, я бы хотел ее почистить:
StageNo ProgramNo CustomerNo ProgramType StageDescription StartDate EndDate
CAPS041835 CAP010611 RL023238 Packaged Nurture 2019-04-04 2019-04-04
CAPS041836 CAP010611 RL023238 Packaged Inactive 2019-04-04 2019-04-04
CAPS041837 CAP010612 RL023238 Pre-Made in Bulk Nurture 2019-04-04 2999-01-01
Я могу пройти и исправить это, как только это будет так. Даже если я оставлю это, это не будет концом света, потому что я могу назначить дату отгрузки как DateTime, а затем +1 секунду, что означает, что продажа упадет только в 1 Программе.
Я начал с написания запроса, чтобы найти промежутки между диапазонами дат, чтобы найти пробелы, где разница в датах меньше 0.
Это то, что я имею до сих пор ...
WITH CustomerProgram AS
(
SELECT
ROW_NUMBER() OVER (ORDER BY [CustomerNo] ASC, [ProgramGroupId] ASC, [StageStartDate] ASC, [StageEndDate] ASC, [StagePrecedence] ASC, [CustomerProgramStageNo] ASC) AS [RowId]
,*
,COUNT([CustomerProgramStageNo]) OVER (PARTITION BY [ProgramGroupId]) AS [StageCount]
FROM
(
SELECT
--RANK() OVER (ORDER BY [CustomerNo] ASC, [ProgramDescription] ASC) AS [ProgramGroupId]
RANK() OVER (ORDER BY [CustomerNo] ASC, [CustomerProgramNo] ASC) AS [ProgramGroupId]
,[CustomerProgramNo]
,[CustomerProgramStageNo]
,[CustomerNo]
,[ProgramCode]
,[ProgramStageCode]
,[ProgramStageDescription]
,CASE [ProgramStageDescription]
WHEN 'Nurture' THEN 1
WHEN 'Graduate' THEN 2
WHEN 'Change Ownership' THEN 3
WHEN 'Restart' THEN 3
WHEN 'Ongoing' THEN 4
WHEN 'Inactive' THEN 5
ELSE NULL
END AS [StagePrecedence]
,CAST([StageStartDate] AS DATETIME) AS [StageStartDate]
,CAST([StageEndDate] AS DATETIME) AS [StageEndDate]
FROM
[CustomerProgramAndStage]
) CustomerProgram
)
,StagesAndGaps AS
(
SELECT
ROW_NUMBER() OVER (ORDER BY [CustomerNo] ASC, [ProgramGroupId] ASC, [StageStartDate] ASC, [StageEndDate] ASC) AS [RowId]
,[ProgramGroupId]
,[StageCount]
,[CustomerNo]
,[DateRangeType]
,[StageStartDate]
,[StageEndDate]
,DATEDIFF(DAY,[StageStartDate],[StageEndDate]) AS [StageDateDayDiff]
,DATEDIFF(YEAR,[StageStartDate],[StageEndDate]) AS [StageDateYearDiff]
,[StartDateRowId]
,[EndDateRowId]
,[PreviousProgramCode]
,[NextProgramCode]
,[PreviousStagePrecedence]
,[NextStagePrecedence]
,[PreviousStageNo]
,[NextStageNo]
FROM
(
SELECT
[ProgramGroupId] AS [ProgramGroupId]
,[StageCount] AS [StageCount]
,[CustomerNo] AS [CustomerNo]
,[DateRangeType] AS [DateRangeType]
,ISNULL([StageStartDate],'1800-01-01') AS [StageStartDate]
,ISNULL([StageEndDate],'3999-01-01') AS [StageEndDate]
,ISNULL([StartDateRowId],0) AS [StartDateRowId]
,ISNULL([EndDateRowId],9999999) AS [EndDateRowId]
,ISNULL([PreviousProgramCode],'Start') AS [PreviousProgramCode]
,ISNULL([NextProgramCode],'End') AS [NextProgramCode]
,ISNULL([PreviousStagePrecedence],0) AS [PreviousStagePrecedence]
,ISNULL([NextStagePrecedence],999) AS [NextStagePrecedence]
,ISNULL([PreviousStageNo],'Start') AS [PreviousStageNo]
,ISNULL([NextStageNo],'End') AS [NextStageNo]
FROM
(
SELECT -- Gaps include time period before the start of a Program
NextStage.[ProgramGroupId] AS [ProgramGroupId]
,NextStage.[StageCount] AS [StageCount]
,NextStage.[CustomerNo] AS [CustomerNo]
,'Gap' AS [DateRangeType]
,PreviousStage.[StageEndDate] AS [StageStartDate]
,NextStage.[StageStartDate] AS [StageEndDate]
,PreviousStage.[RowId] AS [StartDateRowId]
,NextStage.[RowId] AS [EndDateRowId]
,PreviousStage.[ProgramCode] AS [PreviousProgramCode]
,NextStage.[ProgramCode] AS [NextProgramCode]
,PreviousStage.[StagePrecedence] AS [PreviousStagePrecedence]
,NextStage.[StagePrecedence] AS [NextStagePrecedence]
,PreviousStage.[CustomerProgramStageNo] AS [PreviousStageNo]
,NextStage.[CustomerProgramStageNo] AS [NextStageNo]
FROM
(
SELECT
[RowId]
,[ProgramGroupId]
,[StageCount]
,[CustomerProgramStageNo]
,[CustomerNo]
,[ProgramCode]
,[StagePrecedence]
,[StageStartDate]
FROM
CustomerProgram
) NextStage
LEFT JOIN
(
SELECT
[RowId]
,[ProgramGroupId]
,[StageCount]
,[CustomerProgramStageNo]
,[CustomerNo]
,[ProgramCode]
,[StagePrecedence]
,[StageEndDate]
FROM
CustomerProgram
) PreviousStage
ON NextStage.[ProgramGroupId] = PreviousStage.[ProgramGroupId]
AND NextStage.[RowId] - 1 = PreviousStage.[RowId]
UNION
SELECT -- Gaps include time period after the end of a Program (year 2999 if Stage is active)
PreviousStage.[ProgramGroupId] AS [ProgramGroupId]
,PreviousStage.[StageCount] AS [StageCount]
,PreviousStage.[CustomerNo] AS [CustomerNo]
,'Gap' AS [DateRangeType]
,PreviousStage.[StageEndDate] AS [StageStartDate]
,NextStage.[StageStartDate] AS [StageEndDate]
,PreviousStage.[RowId] AS [StartDateRowId]
,NextStage.[RowId] AS [EndDateRowId]
,PreviousStage.[ProgramCode] AS [PreviousProgramCode]
,NextStage.[ProgramCode] AS [NextProgramCode]
,PreviousStage.[StagePrecedence] AS [PreviousStagePrecedence]
,NextStage.[StagePrecedence] AS [NextStagePrecedence]
,PreviousStage.[CustomerProgramStageNo] AS [PreviousStageNo]
,NextStage.[CustomerProgramStageNo] AS [NextStageNo]
FROM
(
SELECT
[RowId]
,[ProgramGroupId]
,[StageCount]
,[CustomerProgramStageNo]
,[CustomerNo]
,[ProgramCode]
,[StagePrecedence]
,[StageEndDate]
FROM
CustomerProgram
) PreviousStage
LEFT JOIN
(
SELECT
[RowId]
,[ProgramGroupId]
,[StageCount]
,[CustomerProgramStageNo]
,[CustomerNo]
,[ProgramCode]
,[StagePrecedence]
,[StageStartDate]
FROM
CustomerProgram
) NextStage
ON PreviousStage.[ProgramGroupId] = NextStage.[ProgramGroupId]
AND PreviousStage.[RowId] + 1 = NextStage.[RowId]
UNION
SELECT -- Stage data
[ProgramGroupId] AS [ProgramGroupId]
,[StageCount] AS [StageCount]
,[CustomerNo] AS [CustomerNo]
,'Stage' AS [DateRangeType]
,[StageStartDate] AS [StageStartDate]
,[StageEndDate] AS [StageEndDate]
,[RowId] AS [StartDateRowId]
,[RowId] AS [EndDateRowId]
,[ProgramCode] AS [PreviousProgramCode]
,[ProgramCode] AS [NextProgramCode]
,[StagePrecedence] AS [PreviousStagePrecedence]
,[StagePrecedence] AS [NextStagePrecedence]
,[CustomerProgramStageNo] AS [PreviousStageNo]
,[CustomerProgramStageNo] AS [NextStageNo]
FROM
CustomerProgram
) StagesAndGaps
) StagesAndGaps
)
SELECT
*
FROM
StagesAndGaps
WHERE
[DateRangeType] = 'Gap'
AND [StageStartDate] NOT IN ('1800-01-01','2999-01-01')
ORDER BY
[RowId] ASC
Я думаю, что я иду в правильном направлении, но я также не уверен, что есть более легкий путь. Извините за длинный пост, но любая помощь будет принята с благодарностью!