ChatGPT解决这个技术问题 Extra ChatGPT

如何正确使用 Oracle ORDER BY 和 ROWNUM?

我很难将存储过程从 SQL Server 转换为 Oracle,以使我们的产品与之兼容。

我有根据时间戳返回某些表的最新记录的查询:

SQL 服务器:

SELECT TOP 1 *
FROM RACEWAY_INPUT_LABO
ORDER BY t_stamp DESC

=> 这将返回我最近的记录

但是甲骨文:

SELECT *
FROM raceway_input_labo 
WHERE  rownum <= 1
ORDER BY t_stamp DESC

=>这将返回我最旧的记录(可能取决于索引),无论 ORDER BY 语句!

我以这种方式封装了 Oracle 查询以满足我的要求:

SELECT * 
FROM 
    (SELECT *
     FROM raceway_input_labo 
     ORDER BY t_stamp DESC)
WHERE  rownum <= 1

它有效。但这对我来说听起来像是一个可怕的黑客攻击,特别是如果我在所涉及的表中有很多记录。

实现这一目标的最佳方法是什么?

您在上一个查询中所做的事情是正确的。您选择记录的有序列表的第一行。简单查询封装。
这在手册中有明确记录:docs.oracle.com/cd/E11882_01/server.112/e26088/…
@a_horse_with_no_name 你的意思是清楚地记录在这个 404 错误中。
@anthonybrice:谢谢。 Oracle 将其所有 URL 更改为手册。最新链接是:docs.oracle.com/cd/E11882_01/server.112/e41084/…

G
Gordon Linoff

where 语句 order by 之前执行。因此,您想要的查询是“取第一行,然后按 t_stamp desc排序”。这不是你想要的。

子查询方法是在 Oracle 中执行此操作的正确方法。

如果您想要一个在两个服务器上都可以使用的版本,您可以使用:

select ril.*
from (select ril.*, row_number() over (order by t_stamp desc) as seqnum
      from raceway_input_labo ril
     ) ril
where seqnum = 1

外部 * 将在最后一列返回“1”。您需要单独列出这些列以避免这种情况。


这不是遍历所有 raceway_input_labo 表并分配行号,然后过滤吗?如果是这样,这不会导致大表出现问题吗?
f
felipe.zkn

请改用 ROW_NUMBER()ROWNUM 是一个伪列,ROW_NUMBER() 是一个函数。您可以阅读它们之间的差异并查看以下查询的输出差异:

SELECT * FROM (SELECT rownum, deptno, ename
           FROM scott.emp
        ORDER BY deptno
       )
 WHERE rownum <= 3
 /

ROWNUM    DEPTNO    ENAME
---------------------------
 7        10    CLARK
 14       10    MILLER
 9        10    KING


 SELECT * FROM 
 (
  SELECT deptno, ename
       , ROW_NUMBER() OVER (ORDER BY deptno) rno
  FROM scott.emp
 ORDER BY deptno
 )
WHERE rno <= 3
/

DEPTNO    ENAME    RNO
-------------------------
10    CLARK        1
10    MILLER       2
10    KING         3

ROWNUM 可能比 ROW_NUMBER() 快,因此是否应该使用其中一个取决于许多因素。
为错误的downvote道歉!不幸的是,我现在无法收回。
u
user3067860

从 Oracle 12c 开始,我们现在有 row limiting clauses 可以做到这一点。

SELECT *
FROM raceway_input_labo 
ORDER BY t_stamp DESC
FETCH FIRST ROW ONLY

或者许多 alternatives 用于不同的场景(前 n 行、平局处理等)。


A
APC

在上面的评论中记录了几个设计问题。简而言之,在 Oracle 中,当您有大型表和/或具有相同列名的表时,您需要手动限制结果(并且您不希望将它们全部显式键入并全部重命名)。简单的解决方案是找出你的断点并在你的查询中限制它。或者,如果您没有冲突的列名约束,您也可以在内部查询中执行此操作。例如

WHERE m_api_log.created_date BETWEEN TO_DATE('10/23/2015 05:00', 'MM/DD/YYYY HH24:MI') 
                                 AND TO_DATE('10/30/2015 23:59', 'MM/DD/YYYY HH24:MI')  

将大大减少结果。然后你可以 ORDER BY 甚至做外部查询来限制行。

另外,我认为 TOAD 具有限制行数的功能;但是,不确定这是否会限制在 Oracle 上的实际查询中。没有把握。


S
SQLer

在这个用例中我建议的替代方法是使用 MAX(t_stamp) 来获取最新的行......例如

select t.* from raceway_input_labo t
where t.t_stamp = (select max(t_stamp) from raceway_input_labo) 
limit 1

我的编码模式偏好(也许) - 可靠,通常比尝试从排序列表中选择第一行执行或更好 - 而且意图更明确易读。希望这可以帮助 ...

SQLer


Oracle 没有限制。你在乞求这个问题。

关注公众号,不定期副业成功案例分享
关注公众号

不定期副业成功案例分享

领先一步获取最新的外包任务吗?

立即订阅