sql中group by用法

说实话,GROUP BY 真的很有趣,因为我经常使用它。
当我第一次接触 SQL 时,我面临着对报告的需求。
老板想按地区和产品线来计算销售额。
我当时就很困惑——如果直接测试肯定不行。
几千条数据堆在一起谁能看得懂?
当时我就在想我该怎么办?查了一下,我突然想到了团购,立马尝试了一下。
像这样编写 SQL:从 Sales 表 Group by Region、Product Line 中选择 Region、Product Line、SUM(Sales)。
结果?报告立即发出!每个区域下面都列出了产品系列的总销量,一目了然。
坦率地说,在那一刻感觉 SQL 开始变得更聪明了。

有趣的是,GROUP BY最大的恐惧是不理解它是如何工作的。
例如,我曾经写过一个嵌套三层GROUP BY的复杂查询,但数据不匹配。
我非常担心,以至于出了很多汗。
后来我了解到,嵌套GROUP BY时,分组的顺序要颠倒过来——先拆分内层,然后向外拆分一层。
就像建造一座大楼一样,首先地基必须稳固,才能在升起时不致倒塌。
我当时没有自己运行,但我记得数据是按照从内到外大致嵌套的顺序执行的。
会更好你自己验证一下吧。

还有另一个危险需要注意。
例如,如果您选择三列,其中一列不在 GROUP BY 中,则 SQL 标准将报告错误。
但是像MySQL这样的一些数据库默认会把不在GROUP BY中的列当作分组列,这一点特别容易让人误解。
正因为如此,我的一位同事跑了几个月的报告,结果数据不正确。
最后他们发现开发环境使用MySQL的默认行为,生产环境使用Oracle。
它立刻就坏了。

但是使用GROUP BY确实可以省去很多麻烦。
例如,上次我为销售部门进行季度分析时,他们想查看按城市、地区和销售渠道划分的转化率。
简单地使用GROUP BY完成分组,然后使用CASE WHEN确定通道,最后计算平均值,全部用一条SQL。
如果我们不使用旧方法,将子查询一层又一层嵌套,这可能需要半夜。
老实说,随着数据量的增长,这种分组和聚合比单独检查每条记录强大一百倍。

当然,团购并不是万能的。
例如,有一次在处理特别脏的数据时,某个字段被填充了空值。
结果分组的时候,直接分成了大量的NULL组。
最终报告看起来很可疑。
这时,你必须首先将零值标记为“未知”或某个默认值是使用COALESCE或IFNULL来处理,这样分组就不会杂乱无章。
数据质量确实需要预先解决。

最后,GROUP BY 是一个强大的分类器。
只有将数据分组才能进行各种比较。
例如,我曾经进行竞品分析,按照使用频率对用户进行分组,然后比较各组的留存率。
只有这样我才能看到哪个产品真正能留住人。
我自己没试过。
我记得在某次分析中,高频组的留存率为6 5 %,中频组的留存率为4 0%,低频组的留存率直接下降到2 5 左右。
具体数字可能还得去验证,但趋势是成立的。

sql 中 ntile 用法_sql 中 ntile 函数分组数据详解

说实话,刚开始接触SQL的时候我并没有完全理解NTILE。
后来实在是被逼的无事可做,才慢慢想出了一些窍门。
这个东西可以说很复杂,也可以说很简单,但它其实有一个核心思想——将排序后的数据均匀地划分到指定数量的桶中。

举一个我亲身经历过的例子。
有一次,我们部门想要分析销售数据,想根据业绩将其分为四个级别(即四分位数)。
当时数据量不小,用GROUP BY直接感觉分组特别不均匀。
后来技术经理说“试试NTILE”,结果确实不错。
具体怎么写已经忘记了,印象是写成NTILE(4 ) OVER(ORDER BY sales DESC)。

有趣的是,NTILE 有一个相当具有欺骗性的功能。
例如,如果你有9 条数据要分为3 个桶,那么前两个桶将各分为3 条,最后一个桶将只有2 条。
当我第一次写查询时,我以为每个桶有4 个条目,但我发现最后一个桶少了一个,这让我很困惑。
后来我才明白,这个东西就是尽可能的分配均匀。
如果不够,就预先分配更多。
这让我想起我在做数据报告的时候,老板盯着最后一桶缺失的数据问为什么。
我当时就绿了。

说到这里,就不得不提一下如何处理数据偏差的问题。
我之前有一个项目。
用户表中有一些非常活跃的用户。
我直接用NTILE来对它们进行分桶。
结果,这些用户就被挤到了一个桶里。
后来我们切换到 NTILE(4 ) OVER (ORDER BY active_days, user_id) 并添加了 user_id 辅助排序,因此可以均匀地分割数据。
这让我意识到,写SQL的时候不能只看表面,要考虑清楚数据的实际分布情况。

我们来谈谈NTILE和其他排名函数的区别。
当我第一次开始使用它时,我经常将 NTILE 和 RANK 混淆。
有一次我想看销量前1 0名,结果却写成NTILE(1 0) OVER (ORDER BY sales DESC)。
结果被分成1 0个桶,每个桶一个数据,这根本不是我想看到的。
后来我发现NTILE是分桶的,RANK是排名的。
这个教训太深刻了,我现在在写 SQL 之前先在纸上画一个示意图。

最后要说的是,不同的数据库对NTILE的支持程度不同。
早年使用MySQL 5 .7 时,NTILE根本不支持。
升级到8 .0后才可以使用。
这让我明白了写SQL不能完全依赖特定数据库的特性,而必须考虑兼容性。
我曾经为客户写过一个SQL脚本,而客户使用的是旧版本的Oracle。
结果我用了NTILE,客户直接报了bug。
实在是太蠢了。

总的来说,NTILE是一个非常方便的功能,但是如果正确使用,需要结合业务场景多思考。
我目前的习惯是在使用 NTILE 之前先运行一小部分数据样本来查看分桶效果,然后大规模使用它。
如今,编写 SQL 并不容易,您必须小心每一步。