【问题标题】:Duplicate rows showing while using group by clause?使用 group by 子句时显示重复的行?
【发布时间】:2019-09-22 03:15:55
【问题描述】:

我编写了一个 SQL 查询,该查询生成如下表。

需要为每个业务将结果分组到一行中。我已经尝试了很多方法,但我无法做到这一点。我尝试将最终表数据插入到临时表中,然后对临时表执行分组,但这不会产生正确的输出。

;WITH Generate_Dates(Start_Date, End_Date) AS (
  SELECT
    CAST(StartDateUtc AS Date),
    CAST(
      CASE WHEN [bg].EndDateUtc IS NULL THEN GETDATE() ELSE CAST([bg].EndDateUtc AS Date) end AS Date
    )
  FROM
    BusinessGoal AS [bg] WITH (NOLOCK)
  WHERE
    [bg].Period = 'Year'
  UNION ALL
  SELECT
    DATEADD(yy, 1, Start_Date),
    End_Date
  FROM
    Generate_Dates
  WHERE
    DATEADD(yy, 1, Start_Date) < End_Date
)
SELECT
  (
    Generate_Dates.Start_Date
  ) AS "Start Period Date",
  (
    Generate_Dates.End_Date
  ) AS "End Period Date",
  [bg].BusinessRefId AS 'Brand',
  (
    CAST (
      [bg].Amount AS DECIMAL
    )
  ) AS "Committed Transaction Fee",
  (
    SELECT
      CAST (
        sum (
          (
            CASE WHEN [s].Credit = 0 THEN - [s].SettlementAmount ELSE [s].SettlementAmount END
          )
        ) AS DECIMAL
      )
  ) AS "Actual Transaction Fee",
  (
    SELECT
      TOP 1 (
        CASE [s].Culture WHEN 'en-US' THEN 'USD' WHEN 'en-CA' THEN 'CAD' WHEN 'en-IE' THEN 'EUR' WHEN 'en-AU' THEN 'AUD' WHEN 'en-NZ' THEN 'NZD' WHEN 'en-Gbg' THEN 'GbgP' WHEN 'es-MX' THEN 'MXN' WHEN 'jp-JP' THEN 'JPY' WHEN 'nbg-NO' THEN 'NOK' end
      )
    FROM
      Settlement AS [s] WITH (NOLOCK)
  ) AS "Currency"
FROM
  BusinessGoal AS [bg] WITH (NOLOCK)
  INNER JOIN Settlement AS [s] WITH (NOLOCK) ON [bg].BusinessRefId = [s].CompanyRefId
  INNER JOIN OrderProductVariant AS [opv] WITH (NOLOCK) ON
  (
    [opv].MRefId = [s].CompanyRefId
    AND [opv].Id = [s].OrderProductVariantId
  )
  INNER JOIN [Order] AS [o] WITH (NOLOCK) ON [o].Id = [opv].OrderId
  INNER JOIN Generate_Dates ON GoalType = 'CommittedTransactionFee'
WHERE
    StartDateUtc <= [s].CreatedOnUtc
    AND (
      (
        EndDateUtc >= [s].CreatedOnUtc
      )
      OR (EndDateUtc is null)
    )
GROUP BY
  Start_Date,
  End_Date,
  BusinessRefId,
  Amount

输出:

Start Period Date End Period Date brand   Committed Transaction Fee 
2019-06-07        2019-08-26  NIKE        45000
2019-06-07        2019-08-26  ADIDAS      18000 
2019-06-07        2019-08-26  ADIDAS      18000 
2019-06-14        2019-08-26  NIKE        45000
2019-06-14        2019-08-26  ADIDAS      18000
2019-06-14        2019-08-26  ADIDAS      18000 
2019-07-25        2019-08-26  NIKE        45000
2019-07-25        2019-08-26  ADIDAS      18000
2019-07-25        2019-08-26  ADIDAS      18000

【问题讨论】:

  • MySQL 还是 SQL Server?
  • MySQL SQL Server。仅在发布问题时标记适当的 RDBMS,而不是使用不同的标记发送垃圾邮件。
  • 轻松为您提供帮助:minimal reproducible example
  • 如果您希望每个业务有一个输出行,则需要按BusinessRefId 分组。然后,您需要决定如何汇总其他列。是否应该对它们进行平均、求和等?
  • 根据您发布的查询,您将其按五列分组!您需要按要对其进行分组的一列对其进行分组。

标签: sql sql-server


【解决方案1】:

这取决于您想要产生的输出。

如果您希望每个企业有一行,但还想返回其他列 (Start Period Date, End Period Date, brand, Committed Transaction Fee),您可能无法使用 GROUP BY,因为您需要将这些列包含在您的 @ 987654325@子句。

您可以使用QUALIFY 函数来执行此操作并仍然返回列,但您必须决定如何“选择”要返回的每一行。例如:

QUALIFY ROW_NUMBER() OVER(
  PARTITION BY [bg].BusinessRefId 
  ORDER BY Generate_Dates.Start_Date DESC
) = 1

执行以下操作:

  1. 根据[bg].BusinessRefId将结果集行分成组
  2. 根据Generate_Dates.Start_Date 对这些组中的行进行排序
  3. 返回每组的第一行

您可以将GROUP BY 子句替换为QUALIFY

WITH Generate_Dates(Start_Date, End_Date) AS (
  SELECT
    CAST(StartDateUtc AS Date),
    CAST(
      CASE 
        WHEN [bg].EndDateUtc IS NULL THEN GETDATE() 
        ELSE CAST([bg].EndDateUtc AS Date) 
      END AS DATE
    )
  FROM BusinessGoal AS [bg] WITH (NOLOCK)
  WHERE [bg].Period = 'Year'

  UNION ALL

  SELECT
    DATEADD(yy, 1, Start_Date),
    End_Date
  FROM Generate_Dates
  WHERE DATEADD(yy, 1, Start_Date) < End_Date
)
SELECT DISTINCT
  Generate_Dates.Start_Date AS 'Start Period Date',
  Generate_Dates.End_Date AS 'End Period Date',
  [bg].BusinessRefId AS 'brand',
  CAST ([bg].Amount AS DECIMAL) AS 'Committed Transaction Fee',
  (
    SELECT
      TOP 1 CAST (
        SUM (
            CASE 
              WHEN [s].Credit = 0 THEN - [s].SettlementAmount 
              ELSE [s].SettlementAmount 
            END
        ) AS DECIMAL
      )
  ) AS 'Actual Transaction Fee',
  (
    SELECT
      TOP 1 (
        CASE [s].Culture 
          WHEN 'en-US' THEN 'USD' 
          WHEN 'en-CA' THEN 'CAD' 
          WHEN 'en-IE' THEN 'EUR' 
          WHEN 'en-AU' THEN 'AUD' 
          WHEN 'en-NZ' THEN 'NZD' 
          WHEN 'en-Gbg' THEN 'GbgP' 
          WHEN 'es-MX' THEN 'MXN' 
          WHEN 'jp-JP' THEN 'JPY' 
          WHEN 'nbg-NO' THEN 'NOK'
        END
      )
    FROM Settlement AS [s] WITH (NOLOCK)
  ) AS 'Currency'
FROM BusinessGoal AS [bg] WITH (NOLOCK)
INNER JOIN Settlement AS [s] WITH (NOLOCK) ON [bg].BusinessRefId = [s].CompanyRefId
INNER JOIN OrderProductVariant AS [opv] WITH (NOLOCK) ON
  (
    [opv].MRefId = [s].CompanyRefId
    AND [opv].Id = [s].OrderProductVariantId
  )
INNER JOIN [Order] AS [o] WITH (NOLOCK) ON [o].Id = [opv].OrderId
INNER JOIN Generate_Dates ON GoalType = 'CommittedTransactionFee'
WHERE StartDateUtc <= [s].CreatedOnUtc
AND (EndDateUtc >= [s].CreatedOnUtc OR EndDateUtc IS NULL)
QUALIFY ROW_NUMBER() OVER(
  PARTITION BY [bg].BusinessRefId 
  ORDER BY Generate_Dates.Start_Date DESC
) = 1
--GROUP BY Start_Date, End_Date, BusinessRefId, Amount, [s].Culture

此外,就像前面提到的海报一样,您不需要其中的DISTINCT。如果你正在做一个没有任何聚合函数的GROUP BY,它在逻辑上等同于做一个DISTINCT

我还没有测试过,所以不确定它是否有效……但可以尝试一下。

【讨论】:

猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2011-09-25
  • 1970-01-01
  • 2020-01-22
  • 2015-12-18
  • 1970-01-01
  • 2016-03-17
  • 2015-09-15
相关资源
最近更新 更多