#sql #oracle #loops #for-loop #subquery
#sql #Oracle #циклы #for-цикл #подзапрос
Вопрос:
Не могли бы вы, пожалуйста, помочь мне переписать следующий запрос внутри запроса цикла FOR в один запрос без цикла:
for rec in select distinct sp.student_id, v.test_id, v.name, p.version_id from student_pages sp, pages p, versions v where p.id = sp.page_id and v.id = p.version_id order by student_id, test_id, name LOOP
select STRING_AGG(cast(p.index as varchar), ';' ORDER BY p.index) as lost_page_indices into l_lost_page_indices from pages p left join student_pages sp on p.id = sp.page_id and sp.student_id = rec.student_id where p.version_id = rec.version_id and sp.page_id is null;
end loop;
В последнем запросе мне нужны следующие поля: sp.student_id, v.test_id, v.name и lost_page_indices.
Комментарии:
1.
string_agg()
В Oracle нет2. Вау, это какой-то запущенный оператор, который у вас есть. Что с предложениями FROM и WHERE после
into l_lost_page_indices
? Было бы лучше начать сначала: описать три базовые таблицы (`student_pages и т. Д.) — Показать имена столбцов и типы данных (ОК, чтобы включать только соответствующие столбцы), обозначения первичного и внешнего ключей, а не ограничения null — и затем, что вы пытаетесь сделать. Объясните на английском языке, предоставьте небольшую выборку входных данных и желаемый результат; не нужно пытаться поместить это в запрос, мы можем помочь с этим.3. Весь цикл выглядит слишком сложным. Вместо того, чтобы пытаться просто переписать цикл, было бы лучше, если бы вы рассказали нам, в чем проблема, которую вы пытаетесь решить. Покажите нам свою структуру таблицы, некоторые примеры данных и ожидаемый результат.
Ответ №1:
Первое сокращение: возьмите запрос, который вы перебираете, превратите его в подзапрос и используйте его как объединенную таблицу.
select STRING_AGG(cast(p.index as varchar), ';' ORDER BY p.index)
as lost_page_indices into l_lost_page_indices
from pages p
join (
select distinct sp.student_id, v.test_id, v.name, p.version_id
from student_pages sp
join pages p on p.id = sp.page_id
join versions v on v.id = p.version_id
) as rec on rec.student_id = sp.student_id
left join student_pages sp on p.id = sp.page_id and
sp.student_id = rec.student_id
where p.version_id = rec.version_id and
sp.page_id is null
order by rec.student_id, rec.test_id, rec.name
Я реорганизовал подзапрос, используя синтаксис соединения для упрощения чтения.
order by
нельзя полагаться на то, что соединение сохранится, поэтому оно перемещается во внешний запрос.
Нет group by
, поэтому я не уверен, будет ли работать агрегатная функция.
И, как указывали другие, string_agg()
не является встроенной функцией Oracle. Вы должны сделать это самостоятельно.
Это можно упростить, между двумя объединениями много избыточности. Этот подзапрос объединяет student_pages, страницы и версии, которые могут быть выполнены с помощью обычного соединения. Единственное, что осталось distinct sp.student_id
, это то, что можно лучше сделать с помощью a group by sp.student_id
.
select STRING_AGG(cast(p.index as varchar), ';' ORDER BY p.index)
as lost_page_indices into l_lost_page_indices
from pages p
left join student_pages sp on sp.page_id = p.id
join versions v on v.id = p.version_id
where sp.page_id is null
group by sp.student_id
order by sp.student_id, v.test_id, v.name
Я не уверен на 100%, что это эквивалентный запрос, но он должен помочь вам начать. Это делает намного понятнее, что делает запрос: найдите потерянные страницы и вставьте их в таблицу.
Комментарии:
1. Большое спасибо! ) Единственное, что условие соединения должно быть: страницы p внутреннее соединение rec на rec.version_id = p.version_id вместо rec.student_id = sp.student_id