Почему этот оператор SQL выводит одну или несколько строк?

#sql #oracle #oracle12c #rownum

#sql #Oracle #oracle12c #rownum

Вопрос:

Мое намерение с помощью следующего оператора 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 может отображать один или несколько кортежей.

Ответ №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

Комментарии:

1. Но эти строки не будут возвращены, потому что первая строка не where соответствует условию и rownum не может быть разреженной.

2. @astentx В середине вложенных запросов, где генерируется, нет фильтра ROWNUM , поэтому все они будут пронумерованы. Фильтр находится на самом внешнем подзапросе.

3. Я ценю ваш полезный комментарий. Я понимаю, КАК мой оператор 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<>скрипка здесь

Комментарии:

1. Спасибо за ваш комментарий. Я попробовал ваше решение. Но просто интересно, почему мой оператор SQL показывает два или более кортежей случайным образом.

2. Синтаксис соединения ANSI не имеет скобок.

3. @WilliamRobertson Да, это так. Вам нужно перейти к документации по условию, где вы найдете это , которое показывает, что составные условия поддерживают окружающие скобки.

4. Нет, условия не требуют скобок, и ваша ссылка содержит примеры условий, например WHERE salary = 2500 , без каких-либо скобок. Ничто в разделе Условий не указывает WHERE на то, что все эти годы мы неправильно писали предложения. ( m.certno = s.presno не является составным условием.)

5. Условия @WilliamRobertson не требуют скобок, однако синтаксически допустимо заключать условия в скобки, поэтому утверждение, что оно «не имеет скобок» (и подразумевает, что оно не должно иметь скобок), неверно. Скобки необязательны и разрешены, а документация, на которую я ссылался, явно включает ( condition ) синтаксис (который классифицируется как составное условие и может быть получен непосредственно из этой части синтаксиса ).