【问题标题】:Average using SQL Group by needs to omit duplicates and group by more than one column平均使用 SQL Group by 需要省略重复和 group by 多于一列
【发布时间】:2017-12-13 20:48:52
【问题描述】:

我正在使用 SQL Server 2016,但我遇到了一个问题,它按多个列进行分组,并在省略重复行的同时找到平均值。我有一个事务表定义为:

CREATE TABLE [dbo].[CUST_TRANSACTION](  
     [EXTRACT_DATE] [date] NULL,
     [CUSTOMER_ID] [bigint] NULL,   
     [TRANS_NUMBER] [bigint] NULL,
     [CATEGORY] [smallint] NULL,    
     [RANKING] [smallint] NULL )

这是一些数据:

EXTRACT_DATE    CUSTOMER_ID TRANS_NUMBER    CATEGORY    RANKING
10/31/2017          10001   1000101              4  100
10/31/2017          10001   1000102              4  100
10/31/2017          10002   1000201              4  200
10/31/2017          10001   1000103              5  100
10/31/2017          10003   1000301              5  300
10/31/2017          10003   1000302              5  300
10/31/2017          10004   1000401              7  500
10/31/2017          10001   1000104              8  100

Customer_Id AND TRANS_NUMBER 组合必须是唯一的,但 customer_id 可以有 1 到多个 Trans_Number,而 Customer_Id 可以存在于 1 到多个类别中。从我查看的数据来看,对于给定的 EXTRACT_DATE,Customer_ID 的排名似乎是相同的。我在排名中没有发现 NULLS,但我确实找到了零,所以我需要从平均值中排除任何零。

请求是生成按每个类别 (1 - 15) 细分的报告并找到该类别中的平均排名,但只计算一次 customer_id 并找到该类别的最大排名。这是针对给定的 EXTRACT_Date。

所以我运行了以下内容:

Select CATEGORY, MAX(RANKING) "Max Ranking", AVG(RANKING) "Average Ranking"
from CUST_TRANSACTION 
where  EXTRACT_DATE = Convert(datetime, '2017-10-31' )
     and RANKING > 1
group by CATEGORY
order by CATEGORY

生成以下输出:

CATEGORY    Max Ranking Average Ranking 
4                 200   133 
5                 300   233 
7                 500   500 
8                 100   100 

但是类别 4 的平均值应该是 150,因为 customer_Id = 10001 有两个条目,类别 5 应该是 = 200,因为 Customer_id 10003 有两个条目。

当我尝试按 Category、Customer_Id 进行分组时,输出包括 Category 和 Customer_Id 的每个组合,这就是 Group by 所做的。所以我不确定我是否需要子选择或任何其他想法?

谢谢

【问题讨论】:

    标签: sql-server


    【解决方案1】:

    您似乎并不关心 trans_number 映射,因此您可以将其删除并在派生表中选择不同的剩余值:

    Select CATEGORY, MAX(RANKING) "Max Ranking", AVG(RANKING) "Average Ranking"
    from ( select distinct [EXTRACT_DATE] ,
                    [CUSTOMER_ID] ,
                    [CATEGORY] ,
                    [RANKING] from CUST_TRANSACTION )CUST_TRANSACTION
    where  EXTRACT_DATE = Convert(datetime, '2017-10-31' )
         and RANKING > 1
    group by CATEGORY
    order by CATEGORY
    

    【讨论】:

    • 谢谢 - 这很好。我在想我需要一个子选择,但我很难将它与 where 子句和 Group by 放在一起。你说得对,我不关心 trans_number。
    【解决方案2】:

    您可以使用公用表表达式 (CTE) 过滤掉某个类别中的重复 customerID。像这样。

    ;with cte as (
    select CATEGORY, RANKING, EXTRACT_DATE
    ROW_NUMBER() over(partition by category, customer_id order by customer_id) rn
    from CUST_TRANSACTION
    )
    Select CATEGORY, MAX(RANKING) "Max Ranking", AVG(RANKING) "Average Ranking"
    from cte --CUST_TRANSACTION 
    where  EXTRACT_DATE = Convert(datetime, '2017-10-31' )
         and RANKING > 1
    and rn = 1
    group by CATEGORY
    order by CATEGORY
    

    【讨论】:

    • 谢谢 - 这也有效。我正在阅读有关过度和分区的内容,需要稍微弄乱它们以更好地理解它们。
    【解决方案3】:

    由于对总体平均值和最大值的不同要求,您不能使用单个列来同时获取两者。子选择将提供一列用于平均,另一列用于最大化。

    DECLARE @QUERY_DATE DATE = '2017-10-31';
    
    Select 
        CATEGORY
        , MAX(RANKING_detail_max) "Max Ranking"
        , AVG(RANKING_detail_sum) "Average Ranking"
    from (
      select CATEGORY
           , CUSTOMER_ID
           , SUM(RANKING) RANKING_detail_sum
           , MAX(RANKING) RANKING_detail_max
      from CUST_TRANSACTION 
      where EXTRACT_DATE = @QUERY_DATE
        and RANKING > 0
      group by CATEGORY, CUSTOMER_ID
    ) rollup
    group by CATEGORY
    order by CATEGORY
    

    【讨论】:

      猜你喜欢
      • 2023-02-11
      • 1970-01-01
      • 2011-10-21
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多