没有 order by 子句的 Oracle 排序结果集

Posted

技术标签:

【中文标题】没有 order by 子句的 Oracle 排序结果集【英文标题】:Oracle ordered resultset without order by clause 【发布时间】:2014-01-01 12:44:47 【问题描述】:

有没有一种方法可以在不实际使用“ORDER BY”子句的情况下从 oracle 表中获取“有序”结果集?

我正在开发一个从 oracle 表(没有唯一列)中读取数据的应用程序,我想引入某种恢复机制,以便在查询失败(例如获取期间的网络错误)的情况下避免读取行已经提取了。

应用程序是使用oracle OCI开发的,目前使用的是简单的选择查询。

是否有任何有效的机制来实现这一点?

【问题讨论】:

恕我直言,如果它没有唯一的列,这不是关系理论意义上的真正表格。您应该添加一些PK并使用它。 在数据仓库中,表中没有主键并不罕见 不,没有ORDER BY,就无法从表中获取一致排序的数据。总是有ROWID,但使用它需要您自担风险。 docs.oracle.com/cd/B19306_01/server.102/b14200/…。但当然,如果删除并插入同一行,它可能会得到不同的 rowid。 【参考方案1】:

在某些非常特殊的情况下,您可以在没有任何 ORDER BY 子句的情况下定义结果顺序。但是,您不应依赖这一点,Oracle 可能随时更改此行为。

也许您可以计算总行数(在查询执行后读取SQL%ROWCOUNT)并检查此数字与您客户端上收到的记录。

【讨论】:

【参考方案2】:

正如 Wernfried 指出的,如果没有 any ORDER BY,就没有可靠的方法来获得有序的结果。但问题假设 ORDER BY 是不可能的,因为没有唯一的列。至少有两种解决方法。

1. ROWID。 每个 Oracle 行都有一个唯一的伪列 ROWID。应用程序可以ORDER BY ROWID,存储最新的ROWID,然后使用WHERE ROWID <= :rowid 从中断处继续。请注意,如果表格被修改或移动,ROWIDs 可以更改。

2。 ROW_NUMBER。 另一种选择是对所有数据进行排序并跟踪重复项。如果两行完全相同,则返回和处理哪些重复并不重要。查询和应用程序只需要跟踪其中有多少已被处理。然后它可以稍后处理其余部分。

drop table test1;

create table test1(a number);
insert into test1 values(1);
insert into test1 values(1);
insert into test1 values(2);
commit;

select a ,row_number() over (order by a /*and all other columns*/) rowNumber
from test1
order by rowNumber

A  ROWNUMBER
1  1          --Am I the real #1?  It doesn't matter.
1  2
2  3

如果在第一行之后出现故障,添加谓词 where rownumber > :last_rownumber_processed 将获取其余行。第二个查询可能返回“第一个”1 而不是“第二个”1,但应用程序不会关心。与第一种解决方法一样,如果数据在运行之间发生变化,这将失败。

无论哪种方式,查询都必须为排序付费:

----------------------------
| Id  | Operation          |
----------------------------
|   0 | SELECT STATEMENT   |
|   1 |  WINDOW SORT       |
|   2 |   TABLE ACCESS FULL|
----------------------------

【讨论】:

【参考方案3】:

案例 1:

为了实现简单的恢复机制,唯一简单的方法就是使用RowID。

select t?.rowid, t1.*, t2.*, t3.* 
 from table1 t1, 
      table2 t2,
      table3 t3
where t1.? = t2.?
  and t2.? = t3.?
  and t?.rowid > :rowidProcessedPriorNetworkFailure
 order by t?.rowid 

t?.rowid 的原因是因为您必须选择叶子表。

在以下情况下,您应该选择 t3 作为 t?。 T2 - T1 :一个 T2 记录可能有一个或多个 T1 记录 T1 - T3 : 一个 T1 记录可能有一个或多个 T3 记录

但请记住,只要 Oracle 维护底层物理结构(即碎片整理、重组、将表移动到新数据文件),RowID 就会发生变化

案例 2:

如果是连接,则选择叶子表。 选择具有最多不同值的列。按该列排序。并且每当您必须恢复时,使用手头上的最后一个值完成反向操作。

希望这会对您有所帮助。

【讨论】:

【参考方案4】:

我使用以下查询来获取有序输出,而不使用“order by”字样。在这里,我想在不使用 order by 子句的情况下对 empno 进行排序。

查询:

Select empno, sal, deptno, max(sal) over(partition by empno) from emp;

但是您可以排除除 empno 和 max() 分析函数之外的任何列。

如果您有任何问题,请告诉我。

【讨论】:

没有。如果没有Order By,则无法保证您的结果将按任何特定顺序排列。 你是想回答还是问什么? 嗨尼克,如果您为查询运行解释计划,“选项”列将具有“排序”。如果您得到不同的结果,请告诉我。

以上是关于没有 order by 子句的 Oracle 排序结果集的主要内容,如果未能解决你的问题,请参考以下文章

Oracle Order By排序用法详解

Oracle系列:order by子句

即使在 VB.NET 中使用 ORDER BY 子句,Oracle DataReader 也会被排序

oracle不可以用order by么

oracle中group by 和order by 同时用

子查询中不允许用order by子句,那么应该怎么办?