`

Oracle中group by 和 having的使用

阅读更多

客户需求分析:

  笔者最近接到一家客户的一个需求。他们部署了一个ERP系统,现在采用的就是Oracle数据库。现在由于企业统计分析的需要,要实现如下的需求。

  1、按月份来统计2009年第一季度每个供应商的采购金额。也就是说,在报表中要能够显示出2009年1月份、2月份、3月份供应商的采购金额合计,不需要明细。

  2、显示的结果按年度、月份、供应商名字进行排序。

   效果图

 

  综合客户的要求,也就是说要实现如上这张报表。

  PL/SQL语句解析:

  select extract(YEAR FROM t.dateordered) AS 年度,extract(MONTH FROM t.dateordered) as 月份,

  p.name as 供应商名字,sum(t.linenetamt) 合计

  from c_orderline2 t

  left join c_bpartner p on p.c_bpartner_id=t.c_bpartner_id

  group by extract(YEAR FROM t.dateordered),extract(MONTH FROM t.dateordered),p.name

  having extract(YEAR FROM t.dateordered)=2009 and extract(MONTH FROM t.dateordered) in (1,2,3)

  order by p.name;

  通过以上语句就可以实现企业如上的需求。在这个需求中,笔者主要用过Group By语句与Having语句来实现。这两个是Oralce数据库中PL/SQL语言中两个很重要的分组语句。利用这个两个语句可以实现一些复杂的统计功能。对于Group By与Having语句的一些基本用法,笔者在这里不做过多描述。笔者这里想说的是,在使用这两个语句进行数据统计时需要注意的地方。在Oracle数据库系统中,对于这两个统计子句做了比较严格的使用限制。数据库管理员必须对这些使用闲置铭记在心,否则的话很容易在统计的过程中遇到错误。具体来说,有如下几个使用限制。

  1、如果选择列表中包含有列、表达式或者分组函数,那么这些列或者表达式必须出现在Group By子句中,否则数据库会提示相关的错误信息。分组函数不用出现在Group By子句中。如上面这个例子,由于在数据库基础表中存储的是下订单的日期,如2009年4月15日。也就是说,年月日是存储在同一个字段中的。但是在统计的时候,需要统计2009年1月、2月、3月的供应商采购金额。为此此时笔者先利用Extract函数从一个日期数据中抽取具体的年、月信息。这个是Oracle数据库中一个很有用的日期函数。要是没有这个函数的话,笔者还需要通过字符串等处理函数来截取年月等信息。由于Extract是一个带函数的表达式,为此其必须出现在Group By子句中。而且注意,笔者此时采用的是表达式本身,而不是其别名。也就是说,笔者没有采用group by年度,月份等表达方法。也就是说,在Group By子句中,必须采用表达式的全称,而不能够采用其别名。否则的话,数据库系统不会接受这个语句。数据库系统之所有要进行类似的控制,其背后藏有比较深层次的原因。不过作为普通数据库管理员来说,不怎么用了解数据库设计背后的内容。只需要把这个规则记在心中即可。这个规则对于大部分数据库管理员来说,可能会经常触犯他。为此笔者再次强调一遍,选择列表中如果包含有列、表达式时,这个列、表达式必须包含在Group By子句中。另外,如果采用了表达式的话,则数据库管理员即使在选择列表中采用了别名,但是在Group By子句中仍然必须采用表达式的完整表达方式,而不能够采用别名。


  如果在一个查询语句中,同时含有Group By(分组语句)、Having(分组语句下的条件函数)、Order By(排序语句)三个共存的话,则需要注意他们有一定的书写顺序。通常情况下Order By排序语句必须放置在最后。如上面的案例中,笔者就把这个排序语句放在最末尾的地方。如果不这么处理的话,系统编译器是不会接受这个PL/SQL语句的。另外需要注意的是,采用Group语句会自动对纪录进行排序。如上面的语句中,笔者并没有对年份、月度进行排序,而只是按供应商名称来进行排序。而现实结果的话,却会自动按年度、月份的大小从小到大来进行排序。这主要因为Group By子句在统计之前,会先对记录按照Group By中的参数从左到右来进行排序,然后再进行统计。如此的话,最后显示的结果就是已经排过序来的结果。如果数据库管理员对于这个排序结果不满意的话,就需要通过Order By子句再来对显示结果进行排序。不过这里需要注意的是,本身分组等子句就需要对纪录进行排序并进行一定的业务逻辑处理,此时会耗费比较多的数据库资源。为此从数据库的性能考虑,在使用Order By排序子句对统计结果进行重新排序的时候,要慎重。如果想把某个字段当作第一顺序排序的话,则只需要把这个字段放置在分组语句中的第一个参数即可。如在上面这个案例中,笔者完全可以通过group by p.name,extract(YEAR FROM t.dateordered),extract(MONTH FROM t.dateordered)这个分组语句来实现结果的排序,而可以不再使用Order By语句。为此只有在必要的情况下,才能够利用Order By子句。

  Group By子句与Where子句是不兼容的。也就是说,在普通的Select等语句中(不含有Group By子句)时可以利用Where子句来过滤显示的结果。但是在上面的语句中,笔者却是使用Having语句来过滤显示结果的。这主要是因为Group By子句与Where子句是不兼容的。也就是说,当要显示分组显示结果时,数据库管理员必须要使用Having子句,而不能够在Where自居中使用分组函数限制分组显示结果。如果数据库管理员在这里触犯这条原则话,那么数据库系统就会拒绝接受这条语句。数据库会提示错误信息,如“命令没有正确结束”等等。另外Having语句主要用来限制分组统计结果,其跟Group By语句是双胞胎。即Having子句必须跟在Group By语句后面使用。其中Group By子句用户对查询结果进行分组统计,而Having子句则用于限制分组显示结果,即根据用户的要求来部分显示所需要的内容。他们是互相配合,分工合作。可以说,如果没有Having语句的帮助,那么Group By语句会失色很多。另外,Having语句对于提高数据库与应用服务器的性能也有很大的关系。由于采用了Having语句来过滤显示的结果,那么其最终符合条件的结果肯定比没有设置限制条件的要少的多。这也就意味着这个显示结果可以减少数据在网络中的传输,最好配上Having 条件过滤语句(虽然这并不属于强制限制)。如在在ERP系统中生成这张报表的时候,可以提示用户输入参数,如需要统计几几年几月份到几几年几月份的采购金额。如果用户没有输入相关的数据的话,则其默认为最近一年的统计数据等等。这虽然是一个小小的技巧,但是在数据量比较多或者数据分组涉及到多张表的情况下,可以非常有效的提高数据库与应用服务器的性能。这是一个强制的条件,数据库管理员必须无条件的遵守。

  需要注意多列分组的顺序问题。group by p.name,extract(YEAR FROM t.dateordered),extract(MONTH FROM t.dateordered 与group by extract(YEAR FROM t.dateordered),extract(MONTH FROM t.dateordered ,p.name这两个分组语句有什么差别吗?如果光从结果上来说,是没有多大差异的。但是从其内部的处理机制上来说,有很大的差别。这主要涉及到多列分组的问题。多列分组时指在Group By子句中使用两个或者两个以上的列生成分组统计结果。当进行多列分组时,汇集于多个列的不同值产生数据统计结果。如上面的例子中,数据库就会根据年份、月份、供应商来生成统计结果。如果用前者的表达方式,则其先统计每个供应商的合计金额,在分类统计年、月的统计金额。简单的说,他们统计顺序不同,但是显示结果相同。这也是第一点所说的,要把选择列表中的字段名、表达式等等全部放入到Group By子句中的原因。只有如此,Group By才会对这些字段进行分组统计。只有如此才能够保证,不会因为Group By子句中的参数顺序不同,而显示不同的统计结果。

  可见Group By分组语句其使用规范要比普通的Select等查询语句要求严格的多。数据库管理员在使用Group语句进行数据分组统计时,一定要注意这些使用限制。否则的话在利用这个分组语句的时候,难免会磕磕碰碰的。

分享到:
评论

相关推荐

    order_by_、group_by_、having的用法

    `GROUPING`函数在某些高级的SQL操作中使用,如`ROLLUP`、`CUBE`和`GROUPING SETS`,用于指示某个表达式在分组过程中是否被聚合。`GROUPING`函数返回1表示该值已被聚合,0表示未被聚合。这个功能在处理多级汇总和分析...

    Oracle中分组查询group by用法规则详解

    在Oracle数据库中,`GROUP BY`子句是一个关键的SQL元素,它允许用户根据一个或多个列的值将数据分组,以便对每个组进行聚合计算。以下是对`GROUP BY`用法的详细解释和规则: 1. **基本用法**: `GROUP BY`子句通常...

    oracle中where 子句和having子句中的区别介绍

    在Oracle数据库中,`WHERE`子句和`HAVING`子句都是用于限制查询结果的条件,但它们在SQL查询中的使用场景和功能有所差异。 首先,`WHERE`子句主要用于在`FROM`子句中指定的表或联接后的结果集上筛选行。它在查询...

    《Pro Oracle SQL》Chapter7--7.10GROUP BY Restrictions

    2. GROUP BY与聚合函数:在使用GROUP BY时,所有未包含在GROUP BY子句中的非聚合列都必须在聚合函数中使用。例如,如果你在SELECT语句中选择了非聚合列,但没有在GROUP BY中列出,那么SQL会抛出错误,因为无法确定...

    深入浅析SQL中的group by 和 having 用法

    然而,某些数据库系统如Oracle允许在`HAVING`中使用未在`SELECT`列表中的列,但这不是标准SQL的行为。 综上所述,`GROUP BY`和`HAVING`是SQL中进行数据分析和统计的重要工具,`GROUP BY`负责分组,`HAVING`负责分组...

    简单讲解sql语句中的group by的使用方法

    - 不能在`WHERE`子句中使用聚合函数,因为`WHERE`是在分组前操作的,而聚合函数需要在分组后使用。如果需要在分组后过滤数据,应该使用`HAVING`子句。 5. **`HAVING`和`WHERE`的区别** - `WHERE`子句在`GROUP BY`...

    group by的详解

    在这个例子中,`GROUP BY`中使用了`extract(YEAR FROM t.dateordered)`和`extract(MONTH FROM t.dateordered)`,而不是它们的别名`年度`和`月份`。 3. **排序顺序**:当同时使用`GROUP BY`、`HAVING`和`ORDER BY`时...

    group by,having,order by的用法详解

    当你在查询中使用了聚合函数(如 COUNT、SUM、AVG、MAX 或 MIN)时,必须使用 `GROUP BY` 来指定这些函数应用于哪些列。这是因为聚合函数计算的是每个分组内的值的总和、平均值等,而不是单个记录的值。例如: ```...

    解决Oracle删除重复数据只留一条的方法详解

    查询及删除重复记录的SQL语句1、查找表中多余的重复记录,重复记录是根据单个字段(Id)来判断select * from 表 where Id in (select Id from 表 group by Id having count(Id) > 1)2、删除表中多余的重复记录,...

    Oracle基础之group by和聚合函数

    当我们刚开始学Oracle时,见到group by,常常会来个三连问:为什么要用group by?group by应该怎么用?为什么写了group by运行时会提示“不是单组分组函数;不符合group by语法”?面对这些问题,我都胆战心惊了...

    oracle group by语句实例测试

    Oracle中的`GROUP BY`语句是SQL查询中的关键部分,用于根据一个或多个列对数据进行分组,以便对每个组执行聚合函数,如`SUM`、`COUNT`、`AVG`等。在本例中,我们看到的`GROUP BY`语句是用来对`test`表中的数据进行...

    sql-Group-by.rar_oracle

    在Oracle数据库中,GROUP BY语句是SQL查询中的一个关键组成部分,它用于对数据进行分组,以便可以对每个分组应用聚合函数,如COUNT、SUM、AVG、MAX和MIN。这个“sql-Group-by.rar_oracle”压缩包文件包含了一个名为...

    使用Group by分组统计.rar

    - 可以在`GROUP BY`语句中使用嵌套分组,先按一个列分组,然后再对每个子组按另一个列进行分组。 6. **分组统计与分析**: - 在业务分析中,`GROUP BY`经常用于获取各类别的统计信息,如产品销售排行、地区销售...

    Oracle中Decode()函数使用技巧

    Decode()函数也可用于GROUP BY、HAVING和ORDER BY子句中,帮助对分组或排序进行条件判断。例如: ``` SELECT DECODE(column, 'value1', 'group1', 'value2', 'group2', 'other') AS group_name, COUNT(*) FROM ...

    sql/having用法

    在 Oracle 中,HAVING 子句是对 GROUP BY 子句的补充,用于对分组后的结果进行筛选。 从上面的例子可以看到,HAVING 子句可以与 GROUP BY 子句结合使用,来对分组后的结果进行筛选。例如,在第一个例子中,HAVING ...

    oracle查询重复数据方法

    Oracle 查询重复数据方法是数据库管理中非常重要的一个问题, Oracle 数据库提供了多种方法来查询和删除重复数据。下面我们将详细介绍几种常见的方法。 方法一:使用 Having 子句 第一种方法是使用 Having 子句来...

    Oracle学习资源与使用

    Oracle学习资源与使用 Oracle是一种关系数据库管理系统...查询结构是SQL语句的基本结构,包括SELECT、FROM、WHERE、GROUP BY和HAVING等子句。查询结构可以用于检索数据、分组数据、排序数据和聚合数据等。 等等...

Global site tag (gtag.js) - Google Analytics