没有聚合函数的 GROUP BY

Posted

技术标签:

【中文标题】没有聚合函数的 GROUP BY【英文标题】:GROUP BY without aggregate function 【发布时间】:2013-12-03 04:24:34 【问题描述】:

我正在尝试理解 (oracle dbms 的新手)。 它是如何运作的? 这是我尝试过的。

我将在其上运行 SQL 的 EMP 表。

SELECT ename , sal
FROM emp
GROUP BY ename , sal

SELECT ename , sal  
FROM emp  
GROUP BY ename;  

结果

ORA-00979:不是 GROUP BY 表达式 00979. 00000 - “不是 GROUP BY 表达式” *原因: *行动: 行错误:397 列:16

SELECT ename , sal  
FROM emp  
GROUP BY sal;  

结果

ORA-00979:不是 GROUP BY 表达式 00979. 00000 - “不是 GROUP BY 表达式” *原因: *操作:行错误:411 列:8

SELECT empno , ename , sal  
FROM emp  
GROUP BY sal , ename;  

结果

ORA-00979:不是 GROUP BY 表达式 00979. 00000 - “不是 GROUP BY 表达式” *原因: *操作:行错误:425 列:8

SELECT empno , ename , sal  
FROM emp  
GROUP BY empno , ename , sal;  

所以,基本上列数必须等于 GROUP BY 子句中的列数,但我仍然不明白为什么或发生了什么。

【问题讨论】:

如果没有聚合函数并且您不介意按升序或降序获取结果,则可以改用排序 (ORDER BY)。 从功能上讲,如果您在选择中使用,那么您只是在执行 DISTINCT。 Oracle 似乎对每种方法都使用了不同的方法,但结果却是相同的。 【参考方案1】:

这就是 GROUP BY 的工作原理。它需要几行并将它们变成一行。因此,它必须知道如何处理某些列(字段)具有不同值的所有组合行。这就是为什么对于要 SELECT 的每个字段都有两个选项:要么将其包含在 GROUP BY 子句中,要么在聚合函数中使用它,以便系统知道您要如何组合字段。

例如,假设您有这张桌子:

Name | OrderNumber
------------------
John | 1
John | 2

如果您说 GROUP BY Name,它如何知道要在结果中显示哪个 OrderNumber?因此,您可以在 group by 中包含 OrderNumber,这将导致这两行。或者,您使用聚合函数来展示如何处理 OrderNumber。例如MAX(OrderNumber),表示结果为John | 2SUM(OrderNumber),表示结果为John | 3

【讨论】:

注意:您还可以拥有不在 GROUP BY 子句中的常量列。但确实所有列都必须属于以下三个类别之一:聚合函数、常量,或者它必须出现在 GROUP BY 子句中。为清楚起见,当我说常量时,我​​的意思是“从 table1 中选择 1 个排序顺序”,您在实际 SQL 中分配一个常量值。 正如@Varun 所说,¡ 有史以来最好的解释!帮助我简单地理解 GROUP BYORDER BY 和聚合函数会发生什么。简单地说,克莱尔,举一个非常简单的例子。 ¡ 非常感谢!【参考方案2】:

鉴于此数据:

Col1  Col2  Col3
 A     X     1
 A     Y     2
 A     Y     3
 B     X     0
 B     Y     3
 B     Z     1

这个查询:

SELECT Col1, Col2, Col3 FROM data GROUP BY Col1, Col2, Col3

将产生完全相同的表。

但是,这个查询:

SELECT Col1, Col2 FROM data GROUP BY Col1, Col2

会导致:

Col1  Col2
 A     X  
 A     Y  
 B     X  
 B     Y  
 B     Z  

现在,一个查询:

SELECT Col1, Col2, Col3 FROM data GROUP BY Col1, Col2

会产生一个问题:带有A,Y的行是两行分组的结果

 A     Y     2
 A     Y     3

那么,Col3 中的值应该是 '2' 还是 '3'?

通常您会使用GROUP BY 来计算,例如一笔:

SELECT Col1, Col2, SUM(Col3) FROM data GROUP BY Col1, Col2

所以在这条线上,我们遇到了一个问题,我们现在得到 (2+3) = 5。

在您的选择中按所有列分组实际上与使用 DISTINCT 相同,在这种情况下最好使用 DISTINCT 关键字词的可读性。

所以不是

SELECT Col1, Col2, Col3 FROM data GROUP BY Col1, Col2, Col3

使用

SELECT DISTINCT Col1, Col2, Col3 FROM data

【讨论】:

SELECT Col1, Col2, Col3 FROM data GROUP BY Col1 会产生什么结果? @SantanuSur 这只会产生我为SELECT Col1, Col2, Col3 FROM data GROUP BY Col1, Col2 解释的相同问题,但有一个额外的问题列。对于 Col1 = A 的行,您希望 Col2Col3 的值是多少? 我只想group the data 一栏 假设我有一个包含 3 列的表...并且第三列有许多重复项..我想提取该表...没有第三列变得混乱...示例第 3 列:- A B A B 我想获得所有具有第 3 列结果的列,如下所示:- A A B B select * from table group by 3rd Column 会起作用吗??【参考方案3】:

您遇到了 GROUP BY 子句的严格要求。不在 group-by 子句中的每一列都必须应用一个函数来将匹配“组”的所有记录减少为单个记录(sum、max、min 等)。

如果您在 GROUP BY 子句中列出所有查询(选择)的列,您实际上是在请求从结果集中排除重复记录。这提供了与 SELECT DISTINCT 相同的效果,后者还从结果集中消除了重复的行。

【讨论】:

【参考方案4】:

没有聚合的 GROUP BY 唯一真正的用例是当您 GROUP BY 的列多于选定的列时,在这种情况下,选定的列可能会重复。否则,您不妨使用 DISTINCT。

值得注意的是,其他 RDBMS 并不要求所有非聚合列都包含在 GROUP BY 中。例如,在 PostgreSQL 中,如果表的主键列包含在 GROUP BY 中,则该表的其他列不需要,因为它们保证对于每个不同的主键列都是不同的。过去,我希望 Oracle 能像在许多情况下为更紧凑的 SQL 所做的那样做同样的事情。

【讨论】:

【参考方案5】:

让我举几个例子。

考虑这些数据。

CREATE TABLE DATASET ( VAL1 CHAR ( 1 CHAR ),
                   VAL2 VARCHAR2 ( 10 CHAR ),
                   VAL3 NUMBER );

INSERT INTO
      DATASET ( VAL1, VAL2, VAL3 )
VALUES
      ( 'b', 'b-details', 2 );

INSERT INTO
      DATASET ( VAL1, VAL2, VAL3 )
VALUES
      ( 'a', 'a-details', 1 );

INSERT INTO
      DATASET ( VAL1, VAL2, VAL3 )
VALUES
      ( 'c', 'c-details', 3 );

INSERT INTO
      DATASET ( VAL1, VAL2, VAL3 )
VALUES
      ( 'a', 'dup', 4 );

INSERT INTO
      DATASET ( VAL1, VAL2, VAL3 )
VALUES
      ( 'c', 'c-details', 5 );

COMMIT;

现在桌子上有什么

SELECT * FROM DATASET;

VAL1 VAL2             VAL3
---- ---------- ----------
b    b-details           2
a    a-details           1
c    c-details           3
a    dup                 4
c    c-details           5

5 rows selected.

--与分组聚合

SELECT
      VAL1,
      COUNT ( * )
FROM
      DATASET A
GROUP BY
      VAL1;

VAL1   COUNT(*)
---- ----------
b             1
a             2
c             2

3 rows selected.

--按多列聚合,但选择部分列

SELECT
      VAL1,
      COUNT ( * )
FROM
      DATASET A
GROUP BY
      VAL1,
      VAL2;

VAL1  
---- 
b             
c             
a             
a             

4 rows selected.

--没有按多列分组的聚合

SELECT
      VAL1,
      VAL2
FROM
      DATASET A
GROUP BY
      VAL1,
      VAL2;

    VAL1  
    ---- 
    b    b-details
    c    c-details
    a    dup
    a    a-details

    4 rows selected.

--没有按多列分组的聚合

SELECT
      VAL1
FROM
      DATASET A
GROUP BY
      VAL1,
      VAL2;

    VAL1  
    ---- 
    b
    c
    a
    a

    4 rows selected.

您在选择中有 N 列(不包括聚合),那么您应该有 N 或 N+x 列

【讨论】:

【参考方案6】:

使用子查询例如:

SELECT field1,field2,(SELECT distinct field3 FROM tbl2 WHERE criteria) AS field3
FROM tbl1 GROUP BY field1,field2

SELECT DISTINCT field1,field2,(SELECT distinct field3 FROM tbl2 WHERE criteria) AS field3
FROM tbl1

【讨论】:

【参考方案7】:

如果 SELECT 子句中有一些列,如果有几行,它将如何选择它?所以是的,SELECT 子句中的每一列也应该在 GROUP BY 子句中,您可以在 SELECT 中使用聚合函数...

您可以在 GROUP BY 子句中包含不在 SELECT 子句中的列,但否则不能

【讨论】:

【参考方案8】:

作为补充

基本上列数必须等于 GROUP BY 子句中的列数

不是一个正确的说法。

任何不属于 GROUP BY 子句的属性都不能用于选择 任何属于 GROUP BY 子句的属性都可以用于选择,但不是强制性的。

【讨论】:

【参考方案9】:

我知道你说过如果你有这样的数据你想了解 group by:

COL-A  COL-B  COL-C  COL-D
  1      Ac      C1     D1
  2      Bd      C2     D2
  3      Ba      C1     D3
  4      Ab      C1     D4
  5      C       C2     D5

你想让数据看起来像:

COL-A  COL-B  COL-C  COL-D
  4      Ab      C1     D4
  1      Ac      C1     D1
  3      Ba      C1     D3
  2      Bd      C2     D2
  5      C       C2     D5

你使用:

select * from table_name
order by col-c,colb

因为我认为这是你打算做的。

【讨论】:

以上是关于没有聚合函数的 GROUP BY的主要内容,如果未能解决你的问题,请参考以下文章

没有聚合函数的 GROUP BY

GROUP BY 子句必须与聚合函数一起使用?

得到 ORA-00979: 不是没有任何聚合函数的 GROUP BY 语句

为啥没有聚合函数的选择列需要成为 MySQL 中 Group by 子句的一部分?

查询没有重复和聚合函数或 GROUP BY 子句问题。 - 重复

聚合函数需要 GROUP BY 吗?