【问题标题】:Oracle ordered resultset without order by clause没有 order by 子句的 Oracle 排序结果集
【发布时间】: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。

标签: sql oracle sql-order-by


【解决方案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,则无法保证您的结果将按任何特定顺序排列。
        • 你是想回答还是问什么?
        • 嗨尼克,如果您为查询运行解释计划,“选项”列将具有“排序”。如果您得到不同的结果,请告诉我。
        猜你喜欢
        • 1970-01-01
        • 2016-01-15
        • 1970-01-01
        • 1970-01-01
        • 2013-10-31
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多