SQL нужно удалить дубликаты элементов из объединения - PullRequest
0 голосов
/ 27 июня 2018

У меня есть запрос, который я пишу. Он собирает некоторые данные из нескольких разных таблиц, а также вычисляет сумму и некоторые средние значения. Первоначально, мой клиент попросил меня выбрать на основе определенных критериев, ограничивая из общего списка частей, однако теперь клиент хочет иметь возможность показать все элементы, даже если они не попадают в критерии. Проблема, с которой я сталкиваюсь, заключается в том, что мой первоначальный запрос, очевидно, ограничивает выбор, потому что для определения определенных критериев необходимо использовать предложение where (например, в зависимости от категории, оно включает результаты только тогда, когда они отрицательные, но не положительные), и при попытке использовать объединение я получаю дубликат записи каждый раз, когда что-то попадает в критерии. Это означает, что мой второй Select получает все, но он не отфильтровывает эту запись, когда она уже была добавлена ​​из первой. Union не считает, что они различны, так как рассчитанные поля отличаются, даже если номер детали совпадает.

Я попытался создать обратный набор условий Где, который просто получит зеркальное отражение первоначального выбора, исключив тем самым возможность дублирования, однако я не могу найти правильные критерии.

Могу ли я получить помощь в создании противоположного выбора для следующего набора условий Где (два параметра деления должны быть одинаковыми для обоих, но создание обратного набора условий для других может работать, я просто не могу разберись как):

WHERE(iitt.Name = 'Invoicing'
      OR iitt.Name = 'Issuing'
      OR (iitt.Name = 'Post Worksheet'
          AND iit.quantity <= 0))
     AND iit.TransactionDate BETWEEN @StartDate AND @EndDate
     AND id.DivisionFK = @division
     AND iit.DivisionNumber = @division

Или какой-то другой метод, позволяющий четко выбирать на основе совпадения только в определенном поле объединения, а не идентичное совпадение для каждого поля, являющееся единственным критерием, по которому фильтрация результатов объединяет результаты? Выберите Distinct или Top 1 не работает. Полный код ниже:

DECLARE @startdate DATE, @enddate DATE, @division INT;
SET @startdate = '5/23/2018';
SET @enddate = '6/26/2018';
SET @division = 2;
SELECT i.PartNumber AS 'Part Number',
       CONVERT(DOUBLE PRECISION, CAST(ABS(SUM(iit.quantity)) AS DECIMAL(19, 0))) AS 'Sum Quantity',
       CONVERT(DOUBLE PRECISION, id.quantityOnHand) AS 'Division Quantity on Hand',
       CASE
           WHEN SUM(iit.quantity) = 0
           THEN 0
           WHEN DATEPART(DAYOFYEAR, @enddate) - DATEPART(DAYOFYEAR, @startdate) = 0
           THEN 0
           WHEN YEAR(@enddate) - YEAR(@startdate) = 1
           THEN CONVERT(DOUBLE PRECISION, CAST(ABS((SUM(iit.quantity) / ((364 - DATEPART(DAYOFYEAR, @startdate)) + DATEPART(DAYOFYEAR, @enddate)))) AS DECIMAL(19, 2)))
           WHEN YEAR(@enddate) - YEAR(@startdate) = 2
           THEN CONVERT(DOUBLE PRECISION, CAST(ABS(SUM(iit.quantity) / ((364 - DATEPART(DAYOFYEAR, @startdate)) + DATEPART(DAYOFYEAR, @enddate) + 364)) AS DECIMAL(19, 2)))
           ELSE CONVERT(DOUBLE PRECISION, CAST(ABS(SUM(iit.quantity) / (DATEPART(DAYOFYEAR, @enddate) - DATEPART(DAYOFYEAR, @startdate))) AS DECIMAL(19, 2)))
       END AS 'Avg Use Per Day',
       CASE
           WHEN SUM(iit.quantity) = 0
           THEN NULL
           WHEN SUM(iit.quantity) / ((364 - DATEPART(DAYOFYEAR, @startdate)) + DATEPART(DAYOFYEAR, @enddate)) = 0
           THEN 0
           WHEN SUM(iit.quantity) / ((364 - DATEPART(DAYOFYEAR, @startdate)) + DATEPART(DAYOFYEAR, @enddate) + 364) = 0
           THEN 0
           WHEN SUM(iit.quantity) / ((364 - DATEPART(DAYOFYEAR, @startdate)) + DATEPART(DAYOFYEAR, @enddate) + 364) = 0
           THEN 0
           WHEN SUM(iit.quantity) / (DATEPART(DAYOFYEAR, @enddate) - DATEPART(DAYOFYEAR, @startdate)) = 0
           THEN 0
           WHEN YEAR(@enddate) - YEAR(@startdate) = 1
           THEN CONVERT(DOUBLE PRECISION, CAST(ABS(ROUND(id.quantityOnHand / ((SUM(iit.quantity) / ((364 - DATEPART(DAYOFYEAR, @startdate)) + DATEPART(DAYOFYEAR, @enddate)))), 2)) AS DECIMAL(19, 2)))
           WHEN YEAR(@enddate) - YEAR(@startdate) = 2
           THEN CONVERT(DOUBLE PRECISION, CAST(ABS(ROUND(id.quantityOnHand / (SUM(iit.quantity) / ((364 - DATEPART(DAYOFYEAR, @startdate)) + DATEPART(DAYOFYEAR, @enddate) + 364)), 2)) AS DECIMAL(19, 2)))
           ELSE CONVERT(DOUBLE PRECISION, CAST(ABS(ROUND(id.quantityOnHand / (SUM(iit.quantity) / (DATEPART(DAYOFYEAR, @enddate) - DATEPART(DAYOFYEAR, @startdate))), 2)) AS DECIMAL(19, 2)))
       END AS 'Depletion Days per Avg Use',
       CONVERT(DOUBLE PRECISION, CAST(ROUND(ii.StandardCost, 3) AS DECIMAL(19, 3))) AS 'Standard Cost'
FROM Item i
     INNER JOIN ItemInventoryTransaction iit ON i.itempk = iit.itemfk
     INNER JOIN ItemInventoryTransactionType iitt ON iitt.ItemInventoryTransactionTypePK = iit.ItemInventoryTransactionTypeFK
     INNER JOIN ItemInventory ii ON i.ItemInventoryFK = ii.ItemInventoryPK
     INNER JOIN ItemDivision id ON i.ItemPK = id.ItemFK
     INNER JOIN Division d ON id.DivisionFK = d.DivisionPK
WHERE(iitt.Name = 'Invoicing'
      OR iitt.Name = 'Issuing'
      OR (iitt.Name = 'Post Worksheet' AND iit.quantity <= 0))
     AND iit.TransactionDate BETWEEN @StartDate AND @EndDate
     AND id.DivisionFK = @division
     AND iit.DivisionNumber = @division
GROUP BY i.PartNumber,
         id.quantityOnHand,
         ii.StandardCost
UNION
SELECT i.PartNumber AS 'Part Number',
       NULL AS 'Sum Quantity',
       CONVERT(DOUBLE PRECISION, id.quantityOnHand) AS 'Division Quantity on Hand',
       NULL AS 'Avg Use Per Day',
       NULL AS 'Depletion Days per Avg Use',
       CONVERT(DOUBLE PRECISION, CAST(ROUND(ii.StandardCost, 3) AS DECIMAL(19, 3))) AS 'Standard Cost'
FROM Item i
     INNER JOIN ItemInventoryTransaction iit ON i.itempk = iit.itemfk
     INNER JOIN ItemInventoryTransactionType iitt ON iitt.ItemInventoryTransactionTypePK = iit.ItemInventoryTransactionTypeFK
     INNER JOIN ItemInventory ii ON i.ItemInventoryFK = ii.ItemInventoryPK
     INNER JOIN ItemDivision id ON i.ItemPK = id.ItemFK
     INNER JOIN Division d ON id.DivisionFK = d.DivisionPK
WHERE id.DivisionFK = @division
      AND iit.DivisionNumber = @division
ORDER BY [Part Number];

1 Ответ

0 голосов
/ 28 июня 2018

Самый простой способ сделать это - добавить предложения WHERE во второй запрос, которые инвертируют то, что фильтрует ваш первый запрос, таким образом избегая дубликатов слова go.

Я предостерегаю от использования агрегатных выражений, таких как MAX, во всем, поскольку это открывает для вас несогласованность данных, если любая из двух повторяющихся записей никогда не будет одинаковой для любых выбранных вами полей, а также медленнее, без причины и менее разборчиво .

Пример ГДЕ, который будет добавлен к вашему второму запросу объединения:

WHERE(iitt.Name <> 'Invoicing'
      AND iitt.Name <> 'Issuing'
      AND (iitt.Name <> 'Post Worksheet'
          OR iit.quantity > 0))
     OR iit.TransactionDate NOT BETWEEN @StartDate AND @EndDate
     OR id.DivisionFK <> @division
     OR iit.DivisionNumber <> @division

Это с вашими вышеуказанными условными обозначениями, инвертированными на основе законов двоичной математики Де-Моргана

...