Oracle仅按一个列分组

3
我有一个包含40列的Oracle数据库表格。 我知道如果我想要进行“group by”查询,选择的所有列都必须在分组中。
我只是想简单地执行:
select col1, col2, col3, col4, col5 from table group by col3

如果我尝试:
select col1, col2, col3, col4, col5 from table group by col1, col2, col3, col4, col5

它没有给出所需的输出。
我已经搜索过了,但没有找到任何解决方案。我发现的所有查询都使用一些类型的Add()或count(*)函数。
在Oracle中,是否不可能简单地按一列分组?
更新:
对不起,我表达得不够清楚。
我的表:
+--------+----------+-------------+-------+
| id     | col1     | col2        | col3  |
+--------+----------+-------------+-------+
| 1      | 1        | some text 1 | 100   |
| 2      | 1        | some text 1 | 200   |
| 3      | 2        | some text 1 | 200   |
| 4      | 3        | some text 1 | 78    |
| 5      | 4        | some text 1 | 65    |
| 6      | 5        | some text 1 | 101   |
| 7      | 5        | some text 1 | 200   |
| 8      | 1        | some text 1 | 200   |
| 9      | 6        | some text 1 | 202   |
+--------+----------+-------------+-------+

通过运行以下查询:

select col1, col2, col3 from table where col3='200' group by col1;

我将获得以下期望的输出:
+--------+----------+-------------+-------+
| id     | col1     | col2        | col3  |
+--------+----------+-------------+-------+
| 2      | 1        | some text 1 | 200   |
| 3      | 2        | some text 1 | 200   |
| 7      | 5        | some text 1 | 200   |
+--------+----------+-------------+-------+

2
你不能这样进行分组。你需要什么?如果你能分享一些样本数据/输出,我们可以帮助你。 - user7392562
使用 order by 代替 group byselect col1,col2,col3,col4,col5 from table order by col3 如果有多个列,则无法按单个列进行分组。 想想看,如果第一行中有 a、b、c,第二行中有 x、y、c。而我们只按第三列分组...系统该选择哪个作为第1和第2列?a还是x?b还是y?系统无法为您决定,因此无效。(虽然在旧版本的MySQL中有效,在当前版本中如果更改设置也是有效的) - xQbert
简单说,在大多数关系型数据库引擎中,没有聚合的情况下进行分组是没有意义的,因为聚合后的行数必须从原始集合减少,而分组表示聚合应发生在哪个级别。当记录中存在重复,并且需要删除重复项时,DISTINCT是有意义的。MySQL扩展了group by,因此在未分组情况下系统会“选择”要显示的内容。它可能选择a或x,可能会因每次执行而异。这就是为什么大多数引擎不扩展group by的原因。 - xQbert
5个回答

7

这里有一段很长的注释;

是的,你不能这样做。想一想...如果你有一个表格如下:

Col1 Col2 Col3
A    A    1
B    A    2
C    A    3

你所做的分组只按照Col2进行,这将会把数据分成一行...那么Col1Col3会发生什么呢?它们都有3个不同的行值。你的DBMS应该如何显示这些呢?

Col1 Col2 Col3
A?   A    1?
B?        2?
C?        3?

这就是为什么你必须按所有列进行分组,否则需要使用聚合或连接它们。(SUM(),MAX(), MIN(), 等等...)

告诉我们你想要的结果是什么样子,我们一定可以帮助你。

编辑-答案:

首先,感谢您更新您的问题。您的查询没有id但是您期望的结果有,所以我将分别回答每个问题。

没有id

为了实现您的目标,仍然需要按所有列进行分组。 让我们来看看这个过程。

如果您在没有任何分组的情况下运行查询:

select col1, col2, col3 from table where col3='200'

您将会收到以下内容:
+----------+-------------+-------+
| col1     | col2        | col3  |
+----------+-------------+-------+
| 1        | some text 1 | 200   |
| 2        | some text 1 | 200   |
| 5        | some text 1 | 200   |
| 1        | some text 1 | 200   |
+----------+-------------+-------+

现在你想只看到 col1 = 1 的行,但是为了这样做,你需要合并所有列,这样你的数据库管理系统才知道如何处理每一列。如果你只尝试按 col1 分组,则数据库管理系统将报错,因为你没有告诉它如何处理 col2col3 中的额外数据:

select col1, col2, col3 from table where col3='200' group by col1 --Errors

+----------+-------------+-------+
| col1     | col2        | col3  |
+----------+-------------+-------+
| 1        | some text 1 | 200   |
| 2        | some text 1 | 200   |
| 5        | some text 1 | 200   |
| ?        | some text 1?| 200?  |
+----------+-------------+-------+

如果您按照这3个条件进行分组,您的数据库管理系统将知道将整行分组在一起(这是您想要的),并且只显示重复的行一次:

select col1, col2, col3 from table where col3='200' group by col1, col2, col3

+----------+-------------+-------+
| col1     | col2        | col3  |
+----------+-------------+-------+
| 1        | some text 1 | 200   |
| 2        | some text 1 | 200   | --Desired results
| 5        | some text 1 | 200   |
+----------+-------------+-------+

使用 id

如果你想要查看 id,你需要告诉你的数据库管理系统展示哪个 id。即使我们按照所有列分组,也无法得到所需的结果,因为 id 列会使每行变得不同(它们将不再组合在一起):

select id, col1, col2, col3 from table where col3='200' group by id, col1, col2, col3

+--------+----------+-------------+-------+
| id     | col1     | col2        | col3  |
+--------+----------+-------------+-------+
| 2      | 1        | some text 1 | 200   | --id = 2
| 3      | 2        | some text 1 | 200   |
| 7      | 5        | some text 1 | 200   |
| 8      | 1        | some text 1 | 200   | --id = 8
+--------+----------+-------------+-------+

因此,为了对这些行进行分组,我们需要明确指定对 id 的操作。根据您所需的结果,您希望选择 id = 2,即最小 id,因此让我们使用 MIN()

select MIN(id), col1, col2, col3 from table where col3='200' group by col1, col2, col3
--Note, MIN() is an aggregate function, so id need not be in the group by

以下代码可以返回你所需的结果(带有 id):

+--------+----------+-------------+-------+
| id     | col1     | col2        | col3  |
+--------+----------+-------------+-------+
| 2      | 1        | some text 1 | 200   |
| 3      | 2        | some text 1 | 200   |
| 7      | 5        | some text 1 | 200   |
+--------+----------+-------------+-------+

最终总结

以下是您需要解决的两个问题:

+--------+----------+-------------+-------+
| id     | col1     | col2        | col3  |
+--------+----------+-------------+-------+
| 2      | 1        | some text 1 | 200   |
| 8      | 1        | some text 1 | 200   |
+--------+----------+-------------+-------+

每当你遇到这些情况时,只需考虑每一列要做什么。在进行分组或聚合时,你需要处理所有列。

  • id,你只想看到id = 2,也就是MIN()
  • co1,你只想看到不同的值,所以使用GROUP BY
  • col2,你只想看到不同的值,所以使用GROUP BY
  • col3,你只想看到不同的值,所以使用GROUP BY

我已经更新了我的问题,请您看一下。 - pro_newbie
@pro_newbie 更新了我的答案。这是概念性的东西,每个人的学习方式都不同。我尝试用几种不同的方式来解释它。希望有所帮助。 - Aaron Dietz
谢谢您详细的解释,我现在对此有了更深入的理解。还有一件事,如果所有的col2值也彼此不同,那么您在“没有id”的部分所解释的方法将不起作用。它会给我返回所有记录。如何处理这种情况? - pro_newbie
@pro_newbie 在这种情况下,你需要决定如何处理 col2。你的选择有:1.) 不选择它。2.) 按它进行分组,但接受行不会合并的事实。(但是,在你的假设中,它们根本不会分组...) 3.) 使用聚合函数仅显示想要的一个 (例如 MIN(),就像我们在 with id 部分所做的那样)。 - Aaron Dietz
4.) 使用LISTAGG()col2的值连接成一个字符串。仅在提取数据时才这样做... 这不是存储数据的好方法。请参见:https://dev59.com/zGfWa4cB1Zd3GeqPj76m - Aaron Dietz
1
非常好的答案!真正一步一步地到达了问题的核心。 - Dan Macak

2

为什么要使用GROUP BY,难道不应该使用ORDER BY吗?

如果您陈述您正在尝试解决的问题的英语版本(即需求),那么更具体的说明会更容易。


2
也许分析函数正是您需要的东西。尝试像这样的东西:
select col1, col2, col3, col4, col5 
, sum(*) over (partition by col1) as col1_summary
, count(*) over () as total_count
from t1 

如果您在谷歌上搜索这篇文章,您会发现数千个示例。例如,这篇介绍分析函数(第一部分)


0
SELECT * FROM table 
WHERE id IN (SELECT MIN(id) FROM table WHERE col3='200' GROUP BY col1)

0

我猜,也许你需要使用upivot函数

或者发布你想要的具体最终结果

select  col3, col_group 
from table
UNPIVOT ( col_group for value in ( col1,col2,col4,col5)) 

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接