没有 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 排序结果集的主要内容,如果未能解决你的问题,请参考以下文章