【问题标题】:Selecting the biggest ZIP code from a column从列中选择最大的邮政编码
【发布时间】:2015-01-07 13:01:23
【问题描述】:

我想获得 DB 中最大的邮政编码。通常我会这样做

SELECT * 
FROM (
   Select * From tbuser ORDER BY zip DESC
) 
WHERE rownum = 1

使用此代码,我可以获得最大的邮政编码值,而不会出现重复行(因为邮政编码不是主键)。

但是日本的主要公司说我不能使用它,因为当连接速度很慢或数据库有非常大的数据时,你无法获得正确的行。如果有人可以提供帮助,对我来说将是一个很大的帮助。

【问题讨论】:

  • 坦率地说,这听起来像是一个错误的限制。但是您使用的是哪个 Oracle 版本?
  • 慢速连接对此没有影响。 Oracle 只会将单行传输回运行该语句的程序。您要么理解错误(关于慢速连接部分),要么说的人不知道 Oracle 如何处理查询。
  • 啊,虽然是最新版本。我不知道为什么,但是日本的主要公司说这个问题并要求我们使用其他方法。很可能我们通过互联网与日本数据库连接。
  • 如果表真的很大,为什么不partition呢?
  • “但是日本的主要公司说我不能使用它,因为当连接速度很慢或数据库有非常大的数据时,” 阅读您的各种 cmets -- 是不是真正的问题“如何在不可靠的连接上检索大行?”

标签: sql oracle greatest-n-per-group


【解决方案1】:

我想获得 DB 中最大的邮政编码。

如果你真的想要邮政编码,试试这个:

SELECT MAX(zip) FROM TBUSER;

这将使用zip 列上的索引(如果存在)。

话虽如此,Oracle 通常足够聪明,可以使用ROWNUM 正确优化子查询选择。也许您的主要公司更关心子查询中可能存在的“全表”̀ORDER BY`? OTH,如果问题确实与“慢速网络”有关,那么如果您的方法确实导致“过度带宽消耗”,那么可能值得花一些时间与您的 DBA 一起使用网络分析器或其他工具查看线路。我对此深表怀疑……


如果您想检索具有最大邮政编码的整行,则an other answer 略有不同(在我看来,这是使用NATURAL JOIN 的罕见情况之一):

select * from t
natural join (select max(zip) zip from t);

当然,如果出现重复,这将返回多行。您必须将其与其他各种答案中发布的几个选项之一结合起来才能仅返回 1 行。

作为一个额外的解决方案,并且由于您不允许使用 ROWNUM(并且假设 row_number 也是任意禁止的),您可以使用以下人为的方法来实现所需的结果:

select * from t
where rowid = (
  select min(t.rowid) rid from t
  natural join (select max(zip) zip from t)
);

http://sqlfiddle.com/#!4/3bd63/5

但老实说,没有任何严肃的理由希望这样的查询比简单的... ORDER BY something DESC) WHERE rownum <= 1 查询执行得更好。

【讨论】:

  • 感谢您的回答西尔万勒鲁。但是 SELECT Max 的主要问题是,如果我有两个最大的邮政编码,例如“99800”,它也会同时显示两行。
  • @Nguyen " 如果我​​有两个最大的邮政编码,例如“99800”,它也会同时显示两行" -- 不,它不会:@987654323 @
  • @SylvainLeroux 呃,我不知道为什么,但它显示两个像 {usera homie 99800 street9999 userb josep 99800 street3453} 我想为您提供一个屏幕截图,但我无法在家中访问。
  • 你到底想要什么结果?具有最大 zip 或最大 zip 的行中的一行的(随机)结果?
  • 只有一行的最大 zip,如果它有更多行具有相同的最大 zip,那么它只显示这些最大 zip 的第一行。并且不能使用 rownum 来做到这一点。
【解决方案2】:

在我看来,这听起来像是来自一个不懂自己在看什么的新手数据库管理员的糟糕建议(通常伪装成规则)。不过,这种洞察力不会对您有所帮助。以“你是个无能的阻挠者”开头的对话很少能取得任何成果。

所以,事情就是这样。首先,您需要确保您的zip 列上有一个索引。它不必是主键。

其次,您可以尝试解释一下,Oracle 的表服务器实际上优化了... ORDER BY something DESC) WHERE rownum <= 1 查询样式。他们的服务器在这方面做得很好。您的用例很常见。

但如果这对您的 DBA 不起作用,请尝试说“我听到了”然后执行此操作。

SELECT * FROM (
    SELECT a.* 
      FROM ( SELECT MAX(zip) zip FROM zip ) b
      JOIN ZIP a ON (a.zip = b.zip)
 ) WHERE rownum <= 1

这将获得具有最高编号 zip 值的一行,而没有您的 DBA 错误地认为会破坏其服务器 RAM 池的 ORDER BY。而且,它相当有效。只要zip 有索引。

【讨论】:

  • 谢谢@Ollie Jones,我明天试试。呃,他们要求不要使用 rownum....
【解决方案3】:

当您现在正在寻找一种无需 rownum 即可获得所需记录的方法时,...

...这是从 Oracle 12c 开始的方法:

select * 
from tbuser
order by zip desc fetch first 1 row only;

...这里是在 Oracle 12c 之前如何做到这一点:

select * 
from (select tbuser.*, row_number() over(order by zip desc) as rn from tbuser)
where rn = 1;

编辑:正如 Sylvain Leroux 所指出的,dbms 对所有记录进行排序而不是仅仅找到最大值需要更多的工作。这是一个没有 rownum 的最大查询:

select * 
from tbuser where rowid =
(select max(rowid) keep (dense_rank last order by zip) from tbuser);

但是正如 Sylvain Leroux 也提到的,列上是否有索引也有区别。我所做的一些测试表明,使用列上的索引,分析函数比传统函数慢。您的原始查询只会进入索引,转到最高值,选择记录然后停止。你不会更快地得到这个。我最后提到的查询在非索引列上的速度非常快,但在索引列上的速度却比你的要慢。

【讨论】:

  • @PIyush 啊,我明白了,对不起
  • 你知道Oracle是否会正确优化这样的查询吗?我有(完全没有根据的)感觉rownum 版本会表现得更好——尽管 OP 的 DBA 声称......
  • @Sylvain Leroux:dbms 必须对所有记录进行排序,然后选择第一个。这与 rownum、row_number 和 fetch first 相同。因此,优化器不会有太多工作要做。
  • @Thorsten "dbms 必须对所有记录进行*排序*" 事实上,我想知道 Oracle 是否能够理解 full sort 在这里不是必需的。它只需要找到最大值。或者当然,在zip 列上有一个适当的索引,因为值已经在索引中排序,所以不需要排序。
  • @Sylvain Leroux:哎呀,你当然是对的,我是短视的。找到最大值并获得该记录当然比对所有记录进行排序要快。我将在我的答案中添加另一个选项和适当的备注。谢谢。
【解决方案4】:

您的要求似乎是任意的,但这应该会给您所要求的结果。

SELECT * 
FROM (SELECT * FROM tbuser 
      WHERE zip = (SELECT MAX(zip) FROM tbuser)) 
WHERE rownum = 1

【讨论】:

  • 我不相信你的原始结果可以在没有rownum的情况下被复制。如果任意用户和地址不重要,您可以执行 SELECT 'genericId', 'genericUser', MAX(zip), 'genericAddress' FROM tbuser
  • 为什么要扫描表两次?它效率不高。在Oracle 12c 中,您可以使用fetch first 1 rows onlyorder by desc
【解决方案5】:

好的 - 试试这样的:

SELECT *
  FROM TBUSER
  WHERE ZIP = (SELECT MAX(ZIP) FROM TBUSER);

根据上述语句从游标中获取一行,然后关闭游标。如果你使用 PL/SQL,你可以这样做:

FOR aRow IN (SELECT *
               FROM TBUSER
               WHERE ZIP = (SELECT MAX(ZIP) FROM TBUSER))
LOOP
   -- Do something with aRow

   -- then force an exit from the loop

   EXIT;
END LOOP;

分享和享受。

【讨论】:

    【解决方案6】:

    我想知道还没有人发布这个答案。我认为是这样,你应该这样做。

    SELECT * 
    FROM (
       Select a.*, max(zip) over () max_zip
       From tbuser a
    ) 
    WHERE zip=max_zip
    and rownum = 1
    

    【讨论】:

    • 谢谢你,但是他们不允许使用rownum。
    • @Nguyen Trong Nhan:无论如何,这个查询和你的一样。但是为什么他们禁止某些查询方式呢?
    • 嗯,他们只给我一个解释,即大型数据库(因为这些数据库在每个病房中存储 jp 人口,所以有时我在第 1 篇文章中发布的代码会给出错误的结果。他们想使用没有 rownum 的另一种方式,但执行时间与 rownum 完全相同。
    【解决方案7】:

    您的查询恰好获得具有最大邮政编码的所有记录中的一个随机行。因此,您检索具有另一个邮政编码或多条记录或零条记录的记录不会是问题(只要表中至少有一条记录)。

    也许日本只是希望其他行中的一个具有该邮政编码?然后,您可能只需要添加另一个订单条件即可获得特定的所需行。

    另一个想法:由于他们在谈论连接速度慢,也可能是他们在一个会话中输入了新的最大邮政编码,与另一个会话查询并获得了旧的最大邮政编码,因为另一个会话的插入语句没有还没通过。但好吧,这就是它的工作方式。

    顺便说一句:选择最大邮政编码是一件奇怪的事情。我想这只是说明问题的一个例子?

    【讨论】:

    • 是的,因为越南的互联网目前非常糟糕。他们希望我们找到一种新方法,从表中最大的列中获取一行中的完整数据。由于连接不好,在DB中执行SQL代码非常困难,因为我们需要先连接到jp DB。
    【解决方案8】:

    如果您使用 MAX 函数获取多条记录(这是不可能的,但在您的情况下,在您发布屏幕截图之前我不知道如何获取)然后您可以在 sql 查询中使用 DISTINCT 来获取单条记录

    SELECT DISTINCT MAX(zipcode) FROM TableUSER
    

    SQL FIDDLE

    【讨论】:

    • 他得到了多条记录,因为他没有选择邮政编码字段,而是选择了整行。
    • @FrumRoll:没有。Nguyen Trong Nhan 发布的查询只选择了一条记录,否则 dbms 存在严重错误。
    • @ThorstenKettner 我的回复是指 Piyush 的声明,即 Nguyen Trong Nhan 表示他在使用 MAX 功能时收到了多条记录。 Nguyen Trong Nhan 的原始查询检索到一条记录是正确的。
    猜你喜欢
    • 1970-01-01
    • 2011-04-11
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2020-04-21
    • 2021-03-30
    • 1970-01-01
    • 2023-02-21
    相关资源
    最近更新 更多