Oracle SQL Как выполнить второе условие только в том случае, если первое не было принято?

#sql #oracle11g #oracle10g

#sql #оракул11g #оракул10g

Вопрос:

Я надеюсь, что кто — нибудь сможет мне помочь. Случай:

У меня есть таблица COMPANY_ACCESS с этими столбцами:

 ID NUMBER, COMPANY_ID NUMBER, AREA_ID NUMBER, TEAM_ID NUMBER, CAN_ACCESS BOOLEAN  

И у меня есть мой запрос (не работает):

 SELECT *  FROM COMPANY_ACCESS ca WHERE   ca.CAN_ACCESS = true  AND ((ca.COMPANY_ID = ?1 AND ca.AREA_ID = ?2 AND ca.TEAM_ID = ?3)  OR (ca.COMPANY_ID = ?1 AND ca.AREA_ID = ?2 AND ca.TEAM_ID IS NULL)  OR (ca.COMPANY_ID = ?1 AND ca.AREA_ID IS NULL AND ca.TEAM_ID IS NULL))  

Каковы мои намерения здесь. Выполните поиск от более конкретного доступа (со всеми параметрами) к менее конкретному. Если у меня есть один регистр в первом условии :

 (COMPANY_ID = ?1 AND AREA_ID = ?2 AND TEAM_ID = ?3)  

Мне не нужно проверять другие и возвращать только этот реестр. Если у меня его нет. Я проверю без идентификатора TEAM_ID (доступ без идентификатора TEAM_ID действителен для всех команд внутри AREA_ID). Но если я выполню этот запрос, я получу регистры в первом условии, во втором условии и в третьем условии. И это не входит в мои намерения. Если бы я нашел его в первом условии (более конкретном) Мне не нужно, чтобы остальные возвращали только этот регистр. Я проверю только второе и третье условие, если раньше ничего не найду в этом условии.

Пожалуйста, кто-нибудь может мне помочь?

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

1. Чтобы уточнить, необязательно ли передаются переменные привязки? Это означает, что если вы передадите только идентификатор компании, он просто вернет доступ к компании? Или будут переданы все параметры, и вы хотите вернуть все, что соответствует какому-либо условию?

2. Все параметры должны быть переданы. И со всеми этими параметрами я буду проверять форму от более конкретной до менее конкретной @Nick

Ответ №1:

В Oracle 12 вы можете отфильтровать строки с помощью переменных привязки, а затем упорядочить результирующий набор так, чтобы сначала были выбраны нужные строки, а затем отфильтровать другие строки с помощью FETCH FIRST ROW WITH TIES :

 SELECT *  FROM COMPANY_ACCESS ca WHERE ca.CAN_ACCESS = true AND ca.COMPANY_ID = ? AND ( (ca.AREA_ID = ? AND (ca.TEAM_ID = ? OR ca.TEAM_ID IS NULL))  OR (ca.AREA_ID IS NULL AND ca.TEAM_ID IS NULL)) ORDER BY  ca.AREA_ID NULLS LAST,  ca.TEAM_ID NULLS LAST FETCH FIRST ROW WITH TIES;  

В более ранних версиях для фильтрации можно использовать аналитические функции:

 SELECT * FROM (  SELECT ca.*,  RANK() OVER (  ORDER BY ca.AREA_ID NULLS LAST, ca.TEAM_ID NULLS LAST  ) AS rnk  FROM COMPANY_ACCESS ca  WHERE ca.CAN_ACCESS = true  AND ca.COMPANY_ID = ?  AND ( (ca.AREA_ID = ? AND (ca.TEAM_ID = ? OR ca.TEAM_ID IS NULL))  OR (ca.AREA_ID IS NULL AND ca.TEAM_ID IS NULL)) ) WHERE rnk = 1;  

Если когда-либо будет только одна совпадающая строка, вы можете использовать ROWNUM вместо этого фильтрацию:

 SELECT * FROM (  SELECT *  FROM COMPANY_ACCESS ca  WHERE ca.CAN_ACCESS = true  AND ca.COMPANY_ID = ?  AND ( (ca.AREA_ID = ? AND (ca.TEAM_ID = ? OR ca.TEAM_ID IS NULL))  OR (ca.AREA_ID IS NULL AND ca.TEAM_ID IS NULL))  ORDER BY  ca.AREA_ID NULLS LAST,  ca.TEAM_ID NULLS LAST ) WHERE ROWNUM = 1;  

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

1. Это работает довольно хорошо. Я не знал, что эта команда ОБНУЛЯЕТСЯ ПОСЛЕДНЕЙ. Есть ли способ упорядочить результаты с регистрами с нулем в конце?

2. @LucasAlves Да.