#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 )
синтаксис (который классифицируется как составное условие и может быть получен непосредственно из этой части синтаксиса ).