【问题标题】:SQL Need to remove duplicate items from a UnionSQL 需要从联合中删除重复项
【发布时间】:2018-12-06 17:00:35
【问题描述】:

我正在写一个查询。它从几个不同的表中收集一些数据,并运行一个总和和一些平均值。 最初,我的客户要求我根据某些标准进行选择,限制在整个零件列表中,但是,现在客户希望能够显示所有项目,即使它们不符合标准。 我遇到的问题是我的初始查询显然限制了选择,因为它需要使用 where 子句来决定某些条件(例如,基于类别,它仅在结果为负时包含结果,但在正时不包含结果)和在尝试使用联合时,只要某些东西确实符合标准,我就会得到一个重复的条目。意思是,我的第二个 Select 得到了所有内容,但是当它已经从第一个添加时,它并没有过滤掉该条目。 Union 不认为这些是不同的,因为计算的字段是不同的,即使部件号是匹配的。

我尝试创建一组反向条件,这些条件将简单地获得初始选择的镜像,从而消除任何重复的可能性,但是,我找不到正确的标准。

我是否可以帮助为以下一组 Where 条件进行相反的选择(两个除法参数必须对两者都相同,但为其他条件创建一组相反的条件可能会起作用,我就是不能弄清楚如何):

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];

【问题讨论】:

  • 默认情况下UNION 表示UNION DISTINCT,因此它应该自行删除所有重复项。但所有列都必须相同,否则它们并不是真正的重复。
  • 请参阅 De Morgan's laws 了解如何反转 ANDOR 条件的组合。
  • 反转条件不是像WHERE NOT (condition) 这么简单吗?
  • 我找到了方法。首先,使联合选择一个With,然后为每个值选择最大值,它将删除重复的行。 With Usage As (...) SELECT MAX([part number]), MAX([Sum Quantity]), MAX([Division Quantity on Hand]), MAX([Avg Use Per Day]), MAX([Depletion Days] per Avg Use]), MAX([Standard Cost]) FROM Usage GROUP BY [part number];

标签: sql tsql duplicates union


【解决方案1】:

执行此操作的简单方法是将 WHERE 子句添加到您的第二个查询中,以反转您的第一个查询过滤器,从而避免单词 go 的重复。

我告诫不要在所有内容中使用 MAX 之类的聚合表达式,因为如果您选择的任何字段的两个重复条目中的任何一个都不相同,这会导致数据不一致,而且它也会无缘无故地变慢并且不太易读.

将 WHERE 添加到联合的第二个查询的示例:

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

这是基于 De-Morgan Laws of Binary Math 反转的上述条件

【讨论】:

    猜你喜欢
    • 2021-01-02
    • 1970-01-01
    • 2018-03-04
    • 1970-01-01
    • 2012-09-06
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2021-04-25
    相关资源
    最近更新 更多