我如何在 Oracle 中获得前 1 名?
Posted
技术标签:
【中文标题】我如何在 Oracle 中获得前 1 名?【英文标题】:How do I do top 1 in Oracle? [duplicate] 【发布时间】:2011-03-27 23:07:11 【问题描述】:如何进行以下操作?
select top 1 Fname from MyTbl
在Oracle 11g?
【问题讨论】:
看看How does one select the TOP N rows from a table How do I limit the number of rows returned by an Oracle query after ordering?的可能重复 你能告诉我们你想要'top 1'的顺序吗? 首先,您永远不应该依赖数据库引擎来做到这一点。如果您想知道这样的事情,请放入音序器。当您这样做时,可以保证它们将按照插入的顺序编号。 关于这个主题的非常有用的材料use-the-index-luke.com/sql/partial-results/top-n-queries 【参考方案1】:如果您只想要第一个选定的行,您可以:
select fname from MyTbl where rownum = 1
您也可以使用解析函数来排序并取顶部 x:
select max(fname) over (rank() order by some_factor) from MyTbl
【讨论】:
如果您只想要 1 行而不关心哪一行,这很好。如果您想要特定的行,例如最近的记录,则需要在子选择中进行排序,例如 Vash 的答案。 Oracle 在排序之前分配 rownums。 @Scott 是的。那是正确的。和帕特里克,好点我认为语法不正确。它真的应该是一个保留(dense_rank()最后......) 第一个例子和第二个例子的区别在于第一个例子选择了A行(任意行,无序)。第二个示例获取第一行的值,而不执行订单内部查询(如下例所示)。 语法不正确: select max(fname) over (rank() order by some_factor) from MyTbl @jclozano “不是一个众所周知的 oracle 功能” - 恕我直言。这很重要,因为“不为人知的功能”往往意味着晦涩难懂,因此可能建议我们应该避免使用。这并不晦涩难懂,不应避免使用它。【参考方案2】:select * from (
select FName from MyTbl
)
where rownum <= 1;
【讨论】:
【参考方案3】:SELECT *
FROM (SELECT * FROM MyTbl ORDER BY Fname )
WHERE ROWNUM = 1;
【讨论】:
这个答案正确地获得了 TOP 行(在限制 ROWNUM 之前对结果进行排序)。 这个答案不是准确的翻译——原始查询没有 ORDER BY,也没有返回表中的所有列。 我的立场是正确的(见下文)。时间到了就会换票。 @OMGPonies 是的。但这可能是大多数人真正想要的,他们通过谷歌搜索他们的问题来此页面 这肯定是该线程中的获胜答案。我可能会添加一条注释,对于top X
,可以将其更改为WHERE ROWNUM <= X
【参考方案4】:
用途:
SELECT x.*
FROM (SELECT fname
FROM MyTbl) x
WHERE ROWNUM = 1
如果使用 Oracle9i+,您可以查看using analytic functions like ROW_NUMBER() but they won't perform as well as ROWNUM。
【讨论】:
不错的答案,但包含一个小错字。你说Oracle9i+不应该是8i吗? download-west.oracle.com/docs/cd/A87860_01/doc/server.817/… @carpenteri:确实,分析在 8i 中可用 - 不记得细节,但直到 9i 才真正向公众提供分析。 小评论 - Vash 下面的答案包括内部查询的 ORDER BY 如果您想要 fname 的 TOP 值而不是“第一”(可以是任何东西,很可能是插入的第一行),这很关键)。可能值得编辑吗? @JulesLt:OP 提供的查询不包含 ORDER BY,因此这是答案代表和准确翻译为 Oracle 语法。 我对 SQL SERVER TOP 语法的误解(错误地认为它类似于 RANK 中的 FIRST,而不是 ROWNUM)。投票赞成。【参考方案5】:我遇到了同样的问题,我可以用这个解决方案解决这个问题:
select a.*, rownum
from (select Fname from MyTbl order by Fname DESC) a
where
rownum = 1
您可以先对结果排序,以便将第一个值放在首位。
祝你好运
【讨论】:
【参考方案6】:你可以这样做
SELECT *
FROM (SELECT Fname FROM MyTbl ORDER BY Fname )
WHERE rownum = 1;
您也可以使用分析函数 RANK 和/或 DENSE_RANK,但 ROWNUM 可能是最简单的。
【讨论】:
你能帮忙举一些排名等的例子吗?【参考方案7】:从表中选择第一行和从表中选择一行是两个不同的任务,需要不同的查询。有很多可能的方法可以做到这一点。其中四个是:
第一
select max(Fname) from MyTbl;
第二
select min(Fname) from MyTbl;
第三
select Fname from MyTbl where rownum = 1;
第四
select max(Fname) from MyTbl where rowid=(select max(rowid) from MyTbl)
【讨论】:
【参考方案8】:使用Oracle 12c(2013 年 6 月),您可以像下面这样使用它。
SELECT * FROM MYTABLE
--ORDER BY COLUMNNAME -OPTIONAL
OFFSET 0 ROWS FETCH NEXT 1 ROWS ONLY
【讨论】:
有趣的命令,我这里用的是12c,OFFSET 0 ROWS
显然不是必须的,你可以使用FETCH NEXT 1 ROWS ONLY
甚至FETCH FIRST ROW ONLY
,顺序很重要,否则相当于只需使用WHERE rownum = 1
。我什至在 OUTER APPLY 指令中尝试过它,它的工作方式与 Ms-SQL 的 TOP 函数一样。
你是对的@RafaelMerlin。在您的帖子之后,我认识到不需要 OFFSET 0 ROWS。在检索 top X 和 top Y 之间的数据时会很有用。
更多例子:oracle-base.com/articles/12c/…
到目前为止一切顺利,但缺少一个重要的点,即TIES
。有关版本12c +
和12c -
发生联系的情况,请参阅this【参考方案9】:
您可以在子查询中使用ROW_NUMBER()
和ORDER BY
子句,并使用此列替换TOP N
。这可以逐步解释。
请参阅下表,其中有两列 NAME
和 DT_CREATED
。
如果您只需要获取前两个日期而不考虑NAME
,则可以使用以下查询。逻辑已经写在查询里面了
-- The number of records can be specified in WHERE clause
SELECT RNO,NAME,DT_CREATED
FROM
(
-- Generates numbers in a column in sequence in the order of date
SELECT ROW_NUMBER() OVER (ORDER BY DT_CREATED) AS RNO,
NAME,DT_CREATED
FROM DEMOTOP
)TAB
WHERE RNO<3;
结果
在某些情况下,我们需要为每个NAME
选择TOP N
结果。在这种情况下,我们可以在子查询中使用PARTITION BY
和ORDER BY
子句。请参考以下查询。
-- The number of records can be specified in WHERE clause
SELECT RNO,NAME,DT_CREATED
FROM
(
--Generates numbers in a column in sequence in the order of date for each NAME
SELECT ROW_NUMBER() OVER (PARTITION BY NAME ORDER BY DT_CREATED) AS RNO,
NAME,DT_CREATED
FROM DEMOTOP
)TAB
WHERE RNO<3;
结果
【讨论】:
使用 ROW_NUMBER()... 是比主题答案更正确的解决方案。此解决方案(以及 max(field) 变体)的一个问题是您无法执行“select ... (select ROW_NUMBER() ... ) for update;” 之类的操作 而且在 PL/SQL 中有时非常重要(抱歉,未能在 5 分钟内编辑之前的评论)。 在这种情况下,我们可以在外部使用 CTE。正确的? @Alexo Po。 我想我不明白你。 for update 子句可以在 ROWID 被 Oracle“轻松”保留时使用。因此分组(以及由于使用分析子句而分组)隐藏了真实的 ROWID 并且无法锁定行。其次,CTE(with (select ... ) as
子句)对这个问题没有任何改变,CTE 只是为了阅读和支持查询。正确的? @Sarath Avanavu
注意我自己。 ROWID 的问题实际上是由于 where RNO 条件而发生的,在这种情况下,RNO 的值与 ROWID 无关,这就是 Oracle 无法锁定行的原因。以上是关于我如何在 Oracle 中获得前 1 名?的主要内容,如果未能解决你的问题,请参考以下文章
如何在 Python 中使用列(Seller_ID、Country、Month、Sales)的卖家表中的每个国家的销售额获得前 10 名卖家 [重复]