СТЕ выдает разный результат при запуске 2 раза подряд

Рейтинг: 0Ответов: 0Опубликовано: 23.04.2023

В хранимой процедуре существует временная таблица #tasks

  CREATE TABLE #tasks (
    FkTaskType INT NOT NULL
   ,DateCreate DATE NOT NULL
   ,DateExpiration DATETIME NOT NULL
   ,ShopId INT NULL
   ,ProductId INT NULL
   ,Reason VARCHAR(128) NULL
   ,NeedRequest BIT NULL
   ,DocumentalRestOnCalculate NUMERIC(18, 3) NULL
   ,AvgSales NUMERIC(18, 3) NULL
   ,SaleAction BIT NULL
   ,MarkdownPerc INT NULL
   ,ManufDate DATE NULL
   ,CountInDelivery NUMERIC(18, 3) NULL
   ,CountMarkDown NUMERIC(18, 3) NULL
   ,Part INT NULL
  )

После заполнения данными выполняется блок кода с CTE который должен удалить дубликаты:

;WITH dupl as(
    SELECT
      FkTaskType
     ,DateCreate
     ,DateExpiration
     ,ShopId
     ,ProductId
     ,Part
     ,NeedRequest
     ,DocumentalRestOnCalculate
     ,ManufDate
     ,CountInDelivery
     ,AvgSales
     ,SaleAction
     ,CountMarkDown
     ,MarkdownPerc
     ,Reason
     ,ROW_NUMBER() OVER (PARTITION BY FkTaskType, DateCreate, DateExpiration, ShopId, ProductId, NeedRequest, DocumentalRestOnCalculate, ManufDate ORDER BY ProductId) Rn
    FROM #tasks)
  DELETE t
  FROM #tasks t
  INNER JOIN dupl d ON (t.FkTaskType = d.FkTaskType AND t.DateCreate = d.DateCreate AND
    t.DateExpiration = d.DateExpiration AND t.ShopId = d.ShopId AND
    ISNULL(t.Reason, '') = ISNULL(d.Reason, '') AND t.Part = d.Part AND
    (t.ProductId = d.ProductId)) OR (t.ProductId IS NULL)
  WHERE d.Rn > 1
  
  SELECT * FROM #tasks t
  WHERE t.ProductId = 148861
  
  RETURN 0

Если запускать ХП 2 раза подряд при одинаковых вводных, данные в #tasks могут отличаться. Причем оба раза часть дубликатов может не удалиться и попасть в конечную выборку: Выборка с дубликатами

Однако если заменить CTE на времянку, такое поведение пропадает и дубликаты удаляются без проблем:

  SELECT
    FkTaskType
   ,DateCreate
   ,DateExpiration
   ,ShopId
   ,ProductId
   ,Part
   ,NeedRequest
   ,DocumentalRestOnCalculate
   ,ManufDate
   ,CountInDelivery
   ,AvgSales
   ,SaleAction
   ,CountMarkDown
   ,MarkdownPerc
   ,Reason
   ,ROW_NUMBER() OVER (PARTITION BY FkTaskType, DateCreate, DateExpiration, ShopId, ProductId, NeedRequest, DocumentalRestOnCalculate, ManufDate ORDER BY ProductId) Rn
  INTO #dupl
  FROM #tasks

  DELETE t
  FROM #tasks t
  INNER JOIN #dupl d ON (t.FkTaskType = d.FkTaskType AND t.DateCreate = d.DateCreate AND
    t.DateExpiration = d.DateExpiration AND t.ShopId = d.ShopId AND
    ISNULL(t.Reason, '') = ISNULL(d.Reason, '') AND t.Part = d.Part AND
    (t.ProductId = d.ProductId)) OR (t.ProductId IS NULL)
  WHERE d.Rn > 1
  
  SELECT * FROM #tasks t
  WHERE t.ProductId = 148861
  
  TRUNCATE TABLE #f  
  
  RETURN 0

ROW_NUMBER() и для CTE dupl и для времянки #dupl всегда выдает корректный результат.
Чем обусловлено такое поведение CTE?
База данных на SQL Server 2019.

Ответы

Ответов пока нет.