【问题标题】:Why this SQL statement outputs one or more rows?为什么这条 SQL 语句会输出一行或多行?
【发布时间】:2020-11-29 11:17:49
【问题描述】:

我通过以下 SQL 语句的意图是随机选择一个元组 表MovieExec, Movie and Studio 的连接结果。 但是这个 SQL 语句输出一个元组,有时是两个或更多元组。 由于条件r = trunc(dbms_random.value(1,6)), 我认为下面的 SQL 语句中不能有两个或更多元组。

select name
from (select e.*, rownum r 
      from  (select movieexec.name, count(*) 
             from movieexec,studio,movie where certno = presno and producerno = certno 
             group by movieexec.name having count(*) = 1) e
      )
where r = trunc(dbms_random.value(1,6));

但是,如果最后一个 where 条件是r = (select trunc(dbms_random.value(1,6)) from dual where rownum =1 ), 它总是只输出一个元组。 我想知道为什么第一个 SQL 语句可以显示一个或多个元组。

【问题讨论】:

    标签: sql oracle oracle12c rownum


    【解决方案1】:

    MTO 明确展示了如何使用正确的语法重写查询。但这不是你要问的问题。你在问为什么你可以得到不止一排。我应该注意,您还可以获得 0 行 - 或最多 6 行的任何数字(尽管这种情况非常罕见)。

    发生了什么?基本答案是在每一行上计算随机值。所以,考虑这样的六行——以及生成的随机值:

      r     random
      1       5
      2       5
      3       3
      4       1
      5       2
      6       6
    

    在这种情况下,第三行和第六行匹配where 条件。因此,您真正要做的是选择前六行的随机子集,其中随机值与 r 匹配。

    还值得注意的是where rownum = 1 将返回一行。但是由于rownum 的工作方式,where rownum = 2 不会返回任何行——因为rownum = 1 必须在rownum 递增到2 之前返回。

    【讨论】:

    • 但不会返回该行,因为第一行不符合where 条件且rownum 不能稀疏。
    • @astentx 在生成ROWNUM 的嵌套查询中间没有过滤器,因此它们都将被编号。过滤器位于最外层的子查询上。
    • 感谢您的有用评论。我了解我的 SQL 语句如何显示多个元组。
    【解决方案2】:

    我在 Oracle 12 上,你可以使用 FETCH FIRST ROW ONLY 随机排序:

    SELECT e.name,
           COUNT(*) 
    FROM   movie m
           INNER JOIN studio s
           ON ( m.certno = s.presno )
           INNER JOIN movieexec e
           ON (  e.producerno = m.certno )
    GROUP BY
           e.name
    HAVING COUNT(*) = 1
    ORDER BY DBMS_RANDOM.VALUE()
    FETCH FIRST ROW ONLY;
    

    (您也可以为表指定别名并使用 ANSI 连接,而不是使用旧的逗号连接。)

    您的查询可以重写为:

    select name
    from (
      select e.*,
             rownum r 
      from   (
        select e.name
        from   movie m
               INNER JOIN studio s
               ON ( m.certno = s.presno )
               INNER JOIN movieexec e
               ON ( e.producerno = m.certno )
        group by e.name
        having count(*) = 1
        order by dbms_random.value()
      ) e
    )
    where r = 1;
    

    db小提琴here

    【讨论】:

    • 感谢您的评论。我试过你的解决方案。但是,只是想知道为什么我的 SQL 语句会随机显示两个或多个元组。
    • ANSI join syntax 没有括号。
    • @WilliamRobertson 是的,确实如此。您需要进入 find this 的 Condition 文档,这表明复合条件支持括号括起来。
    • 不,条件不需要括号,并且您的链接包括不带任何括号的 WHERE salary = 2500 等条件示例。 Conditions 部分中没有任何内容表明这些年来我们一直在写错 WHERE 子句。 (m.certno = s.presno 不是复合条件。)
    • @WilliamRobertson 条件不需要括号,但是,将条件括在括号中在语法上是有效的,因此说它“没有括号”(并暗示它不应该有括号)是不正确的。括号是可选的并且是允许的,我链接到的文档明确包含( condition ) 语法(它被归类为复合条件,可以从this part of the syntax 直接访问)。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2016-08-04
    • 1970-01-01
    • 2014-08-23
    • 1970-01-01
    • 2018-09-06
    • 2019-09-01
    相关资源
    最近更新 更多