139

我很难将存储过程从 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

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

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

4

5 回答 5

134

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”。您需要单独列出这些列以避免这种情况。

于 2013-02-26T14:41:59.780 回答
47

改为使用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
于 2013-02-26T14:47:43.657 回答
5

从 Oracle 12c 开始,我们现在有了行限制子句,可以做到这一点。

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

或者针对不同场景(前 n 行、平局处理等)的许多替代方案。

于 2021-05-12T15:03:10.643 回答
0

在上面的评论中记录了几个设计问题。简短的故事,在 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 上的实际查询中。没有把握。

于 2015-10-23T16:01:29.963 回答
-1

在这个用例中我建议的替代方法是使用 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

于 2016-10-20T12:51:18.537 回答