#sql #oracle #plsql
#sql #Oracle #plsql
Вопрос:
У меня есть запрос с условным предложением WHERE, в котором я выбираю пользователей из Таблицы1 на основе элемента страницы.
Если элемент страницы имеет значение TYPE1 или TYPE2, я выбираю пользователей из Table1, которых нет в Table2, удовлетворяя первому условию, а если пользователь относится к TYPE3, то я выбираю пользователей из Table2, которых нет в Table2, по второму условию.
Теперь мне нужно добавить еще два типа TYPE4 и TYPE5, но трудность в том, что если пользователи относятся к любому из этих типов, они не должны уже существовать в Table2 с status='NEW'
SELECT 1
FROM Table2 b
WHERE b.id = a.id
AND b.type_id = :P2_TEST_TYPE
AND b.status = 'NEW'`
но должен быть в роли «ПЕРВИЧНОГО» и «ВТОРИЧНОГО» соответственно:
mypackage.get_role(a.id) = 'PRIMARY' AND mypackage.get_type_id(TO_NUMBER(:P2_TEST_TYPE))='TYPE4'
И
mypackage.get_role(a.id) = 'SECONDARY' AND mypackage.get_type_id(TO_NUMBER(:P2_TEST_TYPE))='TYPE5'
Запрос, который обрабатывает TYPE1, TYPE2 и TYPE3, приведен ниже. Как я могу включить условия для TYPE4 и TYPE5 в этот запрос:
SELECT a.ID, a.NAME
FROM Table1 a
WHERE NOT EXISTS
(SELECT 1
FROM Table2 b
WHERE b.id = a.id
AND b.type_id = :P2_TEST_TYPE
AND mypackage.get_category_id(b.parent_id) <> mypackage.get_category_id(:P2_PARENT_ID)
AND b.status = 'NEW'
AND mypackage.get_type_id(TO_NUMBER(:P2_TEST_TYPE)) IN ('TYPE1', 'TYPE2')
UNION ALL
SELECT 1
FROM Table2 b
WHERE b.id = a.id
AND b.type_id = :P2_TEST_TYPE
AND b.status = 'NEW'
AND mypackage.get_type_id(TO_NUMBER(:P2_TEST_TYPE)) = 'TYPE3'
);
Комментарии:
1. Примеры данных и желаемых результатов были бы полезны.
2. Разве у вас нет возможности сделать такой условный выбор на уровне обслуживания? (если оно у вас есть)
3. Даже если нет приложения, в которое вы могли бы включить такую логику, что мешает вам создать два или более отдельных запроса, чтобы разбить совокупность? В любом случае, если вам нужно написать свой запрос таким образом, я полагаю, вы найдете оператор sql switch case очень полезным. w3schools.com/sql/sql_case.asp
4. Возможно, было бы проще переключиться на PL / SQL. Я имею в виду: если слишком сложно поместить всю логику в один запрос (не то чтобы его нельзя было написать, но — кто будет его поддерживать? Два месяца спустя вы даже не вспомните, почему именно вы написали это вместо этого ). В (сохраненной) функции у вас есть другой уровень гибкости, и вы можете использовать IFS, CASEs или все, что вам может понадобиться. Если результатом является не одна строка, а несколько из них, пусть функция возвращает таблицу , которую вы можете использовать в Apex как
select * from table(your_function(:P2_TEST_TYPE));
5. Это двухмесячное правило становится еще более важным, если вы будете передавать этот код кому-либо еще. Блок PL / SQL может (и должен) быть подробно прокомментирован.
Ответ №1:
В связи с тем, что оба подзапроса очень похожи, я предлагаю вам извлечь в один подзапрос все общие AND
условия и включить дополнительные OR
для каждого альтернативного условия. Затем сгруппируйте каждый набор условий по их общим подусловиям (тем, которые касаются b.status
):
SELECT a.ID, a.NAME
FROM Table1 a
WHERE NOT EXISTS
(
SELECT 1
FROM Table2 b
WHERE b.id = a.id
AND b.type_id = :P2_TEST_TYPE
AND
(
(
b.status = 'NEW' AND
(
(
mypackage.get_type_id(TO_NUMBER(:P2_TEST_TYPE)) IN ('TYPE1', 'TYPE2')
AND
mypackage.get_category_id(b.parent_id) <> mypackage.get_category_id(:P2_PARENT_ID)
)
OR (mypackage.get_type_id(TO_NUMBER(:P2_TEST_TYPE)) = 'TYPE3')
)
)
OR
(
b.status <> 'NEW' AND
(
(mypackage.get_role(a.id) = 'PRIMARY' AND mypackage.get_type_id(TO_NUMBER(:P2_TEST_TYPE))='TYPE4')
OR (mypackage.get_role(a.id) = 'SECONDARY' AND mypackage.get_type_id(TO_NUMBER(:P2_TEST_TYPE))='TYPE5')
)
)
)
);
Конечно, это создает слишком много сложностей. Вместо этого вам следует рассмотреть возможность использования процедуры на клиентском языке.
Ответ №2:
Решил разделить логику между двумя регионами, а затем использовать show / hide для отображения соответствующего региона