GROUPING SETS特殊用法之grouping__id

文章介绍了在SQL中使用GROUPINGSETS和grouping__id进行多级商品类目汇总的方法。由于不能使用rollup和cube来避免‘全部’ID和名称不匹配的问题,文章详细解释了如何利用grouping__id的按位运算特性,根据不同的二进制位判断是否显示全部,以保证各级类目信息的同步。

GROUPING SETS用法之grouping__id

场景描述

根据月份,多级商品类目(包括id 和 对应的名称) 汇总商品数

当前场景使用不了 rollup 以及 cube ,原因是这里有同级商品类别的id和name,需要保持同步,如果使用cube或者rollup,''
则会出现id,'全部' 或者 '全部',id 的情况出现,但是用grouping__id可以避免这种情况的发生

具体sql代码 及 代码解析


具体的sql:
SELECT 
     IF(GROUPING__ID & 4 = 4, 'ALL' ,lv3_goods_id)           AS  lv3_goods_id  
    ,IF(GROUPING__ID & 4 = 4, '全部',MAX(lv3_goods_name))    AS  lv3_goods_name
    ,IF(GROUPING__ID & 2 = 2, 'ALL' ,lv2_goods_id)           AS  lv2_goods_id  
    ,IF(GROUPING__ID & 2 = 2, '全部',MAX(lv2_goods_name))    AS  lv2_goods_name
    ,IF(GROUPING__ID & 1 = 1, 'ALL' ,lv1_goods_id)           AS  lv1_goods_id  
    ,IF(GROUPING__ID & 1 = 1, '全部',MAX(lv1_goods_name))    AS  lv1_goods_name
    ,count(distinct lv4_goods_id) as lv4_goods_num 
FROM 
    (
    SELECT
         lv1_goods_id
        ,lv1_goods_name
        ,lv2_goods_id
        ,lv2_goods_name
        ,lv3_goods_id
        ,lv3_goods_name
        ,lv4_goods_id
    FROM database.goods_info
    ) t1
GROUP BY 
 lv3_goods_id
,lv2_goods_id
,lv1_goods_id
     GROUPING SETS
     (
         (lv1_goods_id)   
        ,(lv1_goods_id,lv2_goods_id)
        ,(lv1_goods_id,lv2_goods_id,lv3_goods_id)
		,()
     ) 

-------------------------------------- 代码解析 --------------------------------------
4的二进制
0000 0100


-- 跟下面的group by 的字段位置有关
 GROUP BY   
     lv3_goods_id   
    ,lv2_goods_id
    ,lv1_goods_id
      GROUPING SETS
      (
         (lv1_goods_id)   
        ,(lv1_goods_id,lv2_goods_id)
        ,(lv1_goods_id,lv2_goods_id,lv3_goods_id)
	,()
      ) 
		 
		 
四种分组对应的二进制  按位取反  取反后的二进制  我认为取反之后 为1的这个位置是汇总列,所以只有这一列为1,那么就是对应的全部,所以采用按位与的方式
001                   ==>                        110
011                   ==>                        100
111                   ==>                        000
000	              ==>                        111


-- 对于下面的判断
 ,IF(GROUPING__ID & 4 = 4, 'ALL' ,lv3_goods_id)           AS  lv3_goods_id  
 ,IF(GROUPING__ID & 4 = 4, '全部',MAX(lv3_goods_name))    AS  lv3_goods_name
 ,IF(GROUPING__ID & 2 = 2, 'ALL' ,lv2_goods_id)           AS  lv2_goods_id  
 ,IF(GROUPING__ID & 2 = 2, '全部',MAX(lv2_goods_name))    AS  lv2_goods_name
 ,IF(GROUPING__ID & 1 = 1, 'ALL' ,lv1_goods_id)           AS  lv1_goods_id  
 ,IF(GROUPING__ID & 1 = 1, '全部',MAX(lv1_goods_name))    AS  lv1_goods_name
		
		
-- 举例说明 GROUPING__ID & 4 = 4 
4的二进制是 0000 0100 

GROUPING__ID & 4 = 4 

下面四种 按位与 4 后 等于 0000 0100 的组合是    (lv1_goods_id),(lv1_goods_id,lv2_goods_id),()         
0110
0100
0111

即对一级,一级+二级,全部汇总 三种角度去汇总数据时,三级类目使用 "全部" 表示

在这里插入图片描述

在Spark SQL中,`grouping sets`函数和`grouping_id`函数常用于处理多维度组合去重统计的需求。 ### `grouping sets`函数用法 `grouping sets`允许在一个`GROUP BY`子句中定义多个分组集合,从而可以一次性计算多个不同的分组聚合结果。这种方式比使用多个`UNION ALL`语句来实现相同的功能更加简洁高效。例如下面的代码使用`grouping sets`对`temp_tb`表按不同维度组合进行分组: ```sql --spark sql SELECT grouping_id() group_id FROM temp_tb GROUP BY a, b, c, d GROUPING SETS ( (a, b), (a, c), (b, d), (a, d) ); ``` 在这个例子中,`GROUPING SETS`指定了四个不同的分组集合,分别是`(a, b)`、`(a, c)`、`(b, d)`和`(a, d)`,查询会对这四个分组集合分别进行聚合计算。 ### `grouping_id`的使用 `grouping_id`用于标识每个分组集合,它根据分组字段的选择情况生成一个唯一的ID。在Spark SQL中,其规则是维度被选中则为0,没被选中则为1。以之前的例子来说,分组`(a, b)`对应的二进制表示为`0011`,转换为十进制就是`1 + 2 = 3`;分组`(a, c)`对应的二进制是`0101`,十进制为`1 + 4 = 5` ;分组`(b, d)`对应的二进制是`1010`,十进制为`2 + 8 = 10`;分组`(a, d)`对应的二进制是`0110`,十进制为`2 + 4 = 6` [^1]。 `grouping_id`的计算原理如下: 1. 根据`GROUP BY`中字段顺序,若取该字段则是1,否则为0。 2. 将第一步结果,逆序排列得到二进制数值。 3. 将二进制值转化为十进制结果,即为`GROUPING__ID`的值 [^4]。 下面再给出一个使用示例,展示`grouping_id`如何在查询中使用: ```sql SELECT a, b, c, d, grouping_id() as group_id FROM temp_tb GROUP BY a, b, c, d GROUPING SETS ( (a, b), (a, c), (b, d), (a, d) ); ``` 这个查询不仅返回了分组字段,还返回了每个分组集合对应的`grouping_id`,方便区分不同的分组结果。
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值