Как сделать WHERE-CLAUSE в иерархическом запросе в Oracle
В иерархическом запросе Oracle WHERE-CLAUSE должен оцениваться после того, как оператор Connect-By в документе Oracle объявил.
Но есть сложные ситуации: если WHERE-CLAUSE содержит квалификацию в стиле JOIN, как говорит оракул, квалификация Join-Style должна оцениваться перед оператором Connect-By, а другой none-Join-Style, который ссылается только на одно отношение, будет оценивается после оператора Connect-By.
Таким образом, вопрос заключается в следующем: как разделить квалификации в WHERE-CLAUSE на две части: одна оценивается до оператора Connect-By, а другая - после оператора Connect-By.
example:
SQL> desc bar
Name Null? Type
----------------------------------------- -------- -----------------
B1 NUMBER(38)
B2 NUMBER(38)
SQL> desc foo;
Name Null? Type
----------------------------------------- -------- -----------------
F1 NUMBER(38)
F2 NUMBER(38)
SQL> set pagesize 3000
SQL> set linesize 3000
SQL> explain plan for select * from foo, bar where
2 **f1=b1 and (b2 = 1 or f1=b2 and b1=1 or f2=b1+1) and f1 is not null**
3 connect by level < 10;
Explained.
SQL> select * from table(dbms_xplan.display);
PLAN_TABLE_OUTPUT
--------------------------------------------------------------------------------------
Plan hash value: 2657287368
--------------------------------------------------------------------------------------
| Id | Operation | Name | Rows | Bytes | Cost (%CPU)| Time |
--------------------------------------------------------------------------------------
| 0 | SELECT STATEMENT | | 1 | 52 | 5 (20)| 00:00:01 |
|* 1 | FILTER | | | | | |
|* 2 | CONNECT BY WITHOUT FILTERING| | | | | |
|* 3 | HASH JOIN | | 1 | 52 | 5 (20)| 00:00:01 |
| 4 | TABLE ACCESS FULL | FOO | 1 | 26 | 2 (0)| 00:00:01 |
| 5 | TABLE ACCESS FULL | BAR | 1 | 26 | 2 (0)| 00:00:01 |
--------------------------------------------------------------------------------------
Predicate Information (identified by operation id):
---------------------------------------------------
1 - **filter(("B2"=1 OR "B1"=1) AND "F1" IS NOT NULL)**
2 - filter(LEVEL<10)
3 - **access("F1"="B1")**
**filter("F1"="B2" OR "F2"="B1"+1)**
Note
-----
- dynamic sampling used for this statement
24 rows selected.
Таким образом, как показано выше плана, условие в WHERE, f1=b1 и (b2 = 1 или f1=b2 и b1=1 или f2=b1+1) и f1 не является нулевым, стало двумя частями:
один: фильтр (("B2"=1 ИЛИ "B1"=1) И "F1" НЕ НУЛЬ) -> оценивать после подключения
другое: фильтр ("F1"="B2" ИЛИ "F2"="B1"+1) и доступ ("F1" = "B1") -> оценить перед соединением как JOIN-ON
Итак, кто может объяснить, как отличить условия в предложении WHERE и как сформировать две части из предложения WHERE, которое будет применяться до или после соединения?
Благодарю.
Благодарю.
2 ответа
Если вам нужно разделить это явно, вы можете сделать это с помощью круглых и встроенных представлений.
select *
from (select *
from foo, bar
where f1=b1 and (b2 = 1 or f1=b2 and b1=1 or f2=b1+1) and f1 is not null)
connect by level < 10;
Вы не должны использовать неявные объединения, используйте явные JOIN
вместо.
Как только вы это сделаете, вы сможете отличить "реальное" условие где от условия соединения.
Мне не ясно (и это является результатом использования неявного синтаксиса соединения), что именно вы хотите использовать в качестве условия соединения и что использовать в качестве условия where.
Перепишите ваш запрос примерно так:
from foo
join bar on foo.f1 = bar.b1
where bar.b2 = 1 or ....
and f1 is not null
connect by level < 10;
состояние f1 is not null
кажется ненужным (даже в вашем начальном запросе), так как объединение не даст никаких результатов, если f1 равно нулю.