oracle中,还是不甚明白order by和group by的用法

Posted

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了oracle中,还是不甚明白order by和group by的用法相关的知识,希望对你有一定的参考价值。

select * from scott.emp group by deptno (×)
select * from scott.emp order by deptno(√)
还有group by 分组,的顺序怎么回事?
select avg(sal),max(sal) ,job ,deptno from emp group by job, deptno;
回车显示的既不是以job 分组,也不是以deptno分组的。

我甚是理解你 我开始也很不明白
order by是排序
如order by ID 表示按ID 升序排列
order by ID,NUM 表示优先按照ID排序 ID相同的再按NUM排序 这个意思

group by 是分组
首先用group by 的前提是你的select里边用了聚合函数如sum(),avg(),min(),max()
没有聚合函数用不了group by会报错
其次 出现在select里边的除聚合函数以外的所有字段 都必须作为group by的条件
出现在group by中的字段可以不select出来
也就是说 select中的字段必须出现在group by中 group by中的分组条件不一定出现在select中
你的例子中 select * 表示所有字段 这个时候必须所有字段group by 你只group by deptno肯定报错
再次 group by 的顺序类似order by
如 group by A,B,C,D责先按A分组 再按BCD这个顺序分组
group by条件越多分组越细 也就是说 假如A是学校 B是学院 C是专业 D是班级 那最后group by的结果是按照有多少个不同的班级分组 按照最细致的分组

因为我对这个感触颇深希望我的理解对你有帮助追问

最细致的分组,比如说A可以是清华,北大;B是计算机,电子;C是编程技术,网络基础;D是计算机科学班1,电气化科学班2;
那排序是按照计算机科学班1和电气化科学班2分组,但是这两个班既可以是网络专业,也可以是编程技术的,还可以是计算机学院的,也可以是电子学院的。。而且或许是清华的或许是北大的?
还是很乱套的样子。

追答

所以说group by的条件越多 分组越细 越没有意义
给你一个前辈给我讲时的列子你再理解一下:
A B C D 数量
001 B1 C1 D1 10
001 B2 C2 D2 20
002 B3 C3 D3 30
002 B3 C3 D4 40
GROUP BY条件 分组结果求SUM(数量)
A 2行 30
70
A,B 3行 10
20
70
A,B,C 3行 10
20
70
A,B,C,D 4行 10
20
30
40
我觉得这个例子应该很明确分组概念了 你可以理解一下
如果还不明白可以继续探讨

参考技术A

Oracle Order By子句

在Oracle中,表中是以非指定顺序存储行数据记录的,它不管行插入数据库的顺序如何。要按列以升序或降序查询行记录,必须明确指示Oracle数据库要如何去排序。

例如,您可能希望按名称的字母顺序列出所有客户,或者按照从最低到最高信用限额的顺序显示所有客户。

要对数据进行排序,我们可以将ORDER BY子句添加到SELECT语句中,参考以下语法:

要按列排序结果集,可以在ORDER BY子句之后列出该列。

按照列名是一个排序顺序,可以是:

    ASC表示按升序排序

    DESC表示按降序排序

默认情况下,无论是否指定ASC,ORDER BY子句都按升序对行进行排序。如果要按降序对行进行排序,请明确使用DESC。

NULLS FIRST在非NULL值之前放置NULL值,NULLS LAST在非NULL值之后放置NULL值。

ORDER BY子句可以按多列对数据进行排序,每列可能有不同的排序顺序。

请注意,ORDER BY子句总是SELECT语句中的最后一个子句。

GROUP BY 是一个聚合子句,相当于把查询出的结果按某种方式分组。

教程来源:树懒学堂_一站式数据知识平台_Oracle Order By子句

参考技术B order by 顾名思义,就是排序的意思 order by 某列(column) 就是你查看的结果是根据某列的升降序显示的。
group by ,分组函数,关注的是 group by 列,中列的查询结果。当 group by和order by 一起使用时,先执行group by 在执行 order by。

你的sql 使用了聚合函数,是对 avg()max() 列做平均和最大值运算,是以这2个共同结果为分组的。追问

以这两个结果分组?那结果是随意显示的么?既然分组了 怎么看不出谁和谁是一组?

追答

你可以吧查询结果贴出来一下,结果是 以上2个分组+avg()升序来显示。

参考技术C 一个排序 一个分组 怎么不明白呀 不是一个意义呀

一个是用来改结果集的顺序的

一个是用来统计某些字段信息的

group by 不带排序功能

你可以group by了之后 order by 1,2

Oracle LAST_VALUE 仅在分析子句中使用 order by

【中文标题】Oracle LAST_VALUE 仅在分析子句中使用 order by【英文标题】:Oracle LAST_VALUE only with order by in analytic clause 【发布时间】:2019-03-09 12:09:09 【问题描述】:

我有架构(Oracle 11g R2):

CREATE TABLE users (
  id INT NOT NULL,
  name VARCHAR(30) NOT NULL,
  num int NOT NULL
);

INSERT INTO users (id, name, num) VALUES (1,'alan',5);
INSERT INTO users (id, name, num) VALUES (2,'alan',4);
INSERT INTO users (id, name, num) VALUES (3,'julia',10);
INSERT INTO users (id, name, num) VALUES (4,'maros',77);
INSERT INTO users (id, name, num) VALUES (5,'alan',1);
INSERT INTO users (id, name, num) VALUES (6,'maros',14);
INSERT INTO users (id, name, num) VALUES (7,'fero',1);
INSERT INTO users (id, name, num) VALUES (8,'matej',8);
INSERT INTO users (id, name, num) VALUES (9,'maros',55);

我执行以下查询 - 仅使用 LAST_VALUE 分析函数和 ORDER BY 分析子句:

我的假设是这个查询在一个分区上执行——整个表(因为缺少 partition by 子句)。它将在给定分区(整个表)中按名称对行进行排序,并将使用默认窗口子句RANGE BETWEEN UNBOUNDED PRECEDING AND CURRENT ROW

select us.*, 
last_value(num) over (order by name) as lv 
from users us;

但是上面执行的查询将给出与下面的完全相同的结果。我对第二个查询的假设是,该查询首先按名称对表行进行分区,然后按 num 对每个分区中的行进行排序,然后在每个分区上应用窗口子句 RANGE BETWEEN UNBOUNDED PRECEDING AND UNBOUNDED FOLLOWING 以获得 LAST_VALUE

select us.*, 
last_value(num) over (partition by name order by num RANGE BETWEEN UNBOUNDED PRECEDING AND UNBOUNDED FOLLOWING) as lv 
from users us;

我的一个假设显然是错误的,因为上述两个查询给出了相同的结果。看起来第一个查询订单记录也是幕后的 num。您能否指出我的假设有什么问题以及为什么这些查询返回相同的结果?

【问题讨论】:

【参考方案1】:

答案很简单。无论出于何种原因,当在窗口子句中使用 logical (RANGE) 偏移量时(显式或隐式 - 默认情况下),Oracle 选择使 LAST_VALUE 具有确定性。具体来说,在这种情况下,测量表达式的 HIGHEST 值是从由order by 排序绑定的一组行中选择的。

https://docs.oracle.com/en/database/oracle/oracle-database/12.2/sqlrf/LAST_VALUE.html#GUID-A646AF95-C8E9-4A67-87BA-87B11AEE7B79

在 Oracle 文档中该页面的底部,我们可以阅读:

当发现 ORDER BY 表达式重复时,LAST_VALUEexpr [...]

的最大值

为什么文档在 examples 部分中这么说,而不是在函数的解释中?因为,通常情况下,文档似乎不是由合格的人编写的。

【讨论】:

the documentation doesn't seem to be written by qualified people. ... MySQL(也属于 Oracle)的文档也偶尔会出现问题。更大的问题是文档非常庞大,而他们拥有的给定规模的团队只能处理这么多。 @TimBiegeleisen - 这可能是真的。但是第一次将某些内容放在示例部分(在其他任何地方都没有提及)表明缺乏资格,除了您提到的其他内容之外,这可能也是正确的。 @mathguy 为什么没有指定“分区依据”时所有行的 LV=8?不应该考虑所有行,按名称和从最后一行获取的值排序,在本例中是 name='matej' 的行,所以 LV 将是 8? @Marko - 您指的是 OP 的第一个查询吗?如果您不指定分区并且您指定range between unbounded preceding and unbounded following,您所说的应该会发生 - 您是否尝试过这种方式?默认的窗口子句(在 OP 的第一个查询中使用)是 range between unbounded preceding and current row,这不是一回事。【参考方案2】:

Here 是一个 dbfiddle,以防有人想和他们一起玩。

假设您认为第二个查询返回了正确的结果。

select us.*,
       last_value(num) over (partition by name
                             order by num
                             RANGE BETWEEN UNBOUNDED PRECEDING AND UNBOUNDED FOLLOWING
                            ) as lv
from users us;

我还要指出,这更简洁地写成:

select us.*,
       max(num) over (partition by name
                      order by num
                     ) as lv
from users us;

这与你的问题无关,但我想指出。

现在,为什么会给出相同的结果?

select us.*,
       last_value(num) over (order by name) as lv
from users us;

好吧,没有窗口子句,这相当于:

select us.*,
       last_value(num) over (order by name
                             range between unbounded preceding and current row
                            ) as lv
from users us;

range 在这里非常重要。它不会转到当前行。它转到name 中具有相同值的所有行。

根据我对 order by 相关文档的理解,any num 值可以从具有相同名称的行中选择。为什么? SQL(和 Oracle)中的排序不稳定。这意味着不能保证保留行的原始顺序。

在这种特殊情况下,最后一个值恰好是最大值可能是巧合。或者,出于某种原因,Oracle 可能会出于某种原因将num 添加到排序中。

【讨论】:

感谢您的回答。我已经进行了多次尝试,这似乎不是巧合,因为始终选择正确的值作为 last_value。我同意似乎由于某种原因执行了按 num 排序,但找不到任何官方信息来支持这一说法。顺便提一句。您的第二个简洁编写的查询不会返回与第一个相同的行集。您必须省略“order by”,因为这会引入默认窗口(并且在使用“max”分析函数时也没有效果) @EddGarcia 。 . .我意识到这一点。我无法解释这种行为。然而,“正确值”不是最高值;相同名称的任何值都是等效的。选择最高值似乎是 Oracle 工作方式的产物。为此,我强烈建议您使用 MAX() “在我的阅读中”,你说。读书,从哪里来?之后你所说的非常明智(一个非常好的假设),但你没有在任何地方读过它。事实上,Oracle 文档的说法恰恰相反。当在窗口子句中使用range 时,Oracle 选择 使函数确定性。他们通过始终从绑定的行中选择最大的值来做到这一点。 @mathguy 。 . .你有这方面的参考吗? 是的,我刚刚发布了。【参考方案3】:

来自 Oracle 杂志中的 this blog,如果您在窗口函数中使用 ORDER BY 子句而不指定其他任何内容,会发生以下情况:

一个 ORDER BY 子句,在没有任何进一步的窗口子句参数的情况下,有效地添加了一个默认的窗口子句:RANGE UNBOUNDED PRECEDING,这意味着,“当前分区中的当前行和以前的行是应该在计算。”当 ORDER BY 子句没有伴随 PARTITION 子句时,分析函数使用的整个行集都是默认的当前分区。

所以,你的第一个查询实际上是这样的:

SELECT us.*, LAST_VALUE(num) OVER (ORDER BY name RANGE UNBOUNDED PRECEDING) AS lv
FROM users us;

如果您运行上述查询,您将获得您所看到的当前行为,这将为每个名称返回一个单独的最后一个值。这与以下查询不同:

SELECT
    us.*,
    LAST_VALUE(num) OVER (ORDER BY name
        RANGE BETWEEN UNBOUNDED PRECEDING AND UNBOUNDED FOLLOWING) AS lv
FROM users us;

这只是为num的最后一个值生成值8,它对应于matej的值,matej是姓名升序排序时的姓。

【讨论】:

所有这些可能都是正确的,但它甚至与 OP 的问题没有任何重叠,即:为什么第一个查询返回 出现的结果使用决胜局——就好像order by 子句是order by name, num。这个问题有一个非常简单的答案,但不是你给出的答案。 @mathguy and it will use default windowing clause RANGE BETWEEN UNBOUNDED PRECEDING AND CURRENT ROW ...我的回答实际上确实解决了 OP 的一些疑问。他引用的窗口不是默认窗口,它解释了 OP 当前的观察结果。 错误...你让事情变得更糟了。 RANGE BETWEEN UNBOUNDED PRECEDING AND CURRENT ROW 默认的窗口子句。 RANGE UNBOUNDED PRECEDING 是相同的简写,但 Oracle 文档实际上使用简写:如果您完全省略 windowing_clause,则默认为 RANGE BETWEEN UNBOUNDED PRECEDING AND CURRENT ROW 例如此处:docs.oracle.com/cd/E11882_01/server.112/e41084/…

以上是关于oracle中,还是不甚明白order by和group by的用法的主要内容,如果未能解决你的问题,请参考以下文章

Oracle LAST_VALUE 仅在分析子句中使用 order by

oracle使用order by排序null值如何处理

Oracle order by 处理NULL值

oracle中group by 和order by 同时用

oracle不可以用order by么

Oracle Order By排序用法详解