Дополнительное предложение WHERE с более чем 3 условиями

#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 для отображения соответствующего региона