Почему CONNECT BY LEVEL в таблице возвращает дополнительные строки?
использование CONNECT by LEVEL, похоже, возвращает слишком много строк при выполнении на таблице. Какова логика происходящего?
предполагая следующую таблицу:
create table a ( id number );
insert into a values (1);
insert into a values (2);
insert into a values (3);
этот запрос возвращает 12 строк (SQL Fiddle).
select id, level as lvl
from a
connect by level <= 2
order by id, level
одна строка для каждой в таблице A со значением столбца LVL равным 1 и три для каждой в таблице A, где столбец LVL равен 2, т. е.:
ID | LVL ---+----- 1 | 1 1 | 2 1 | 2 1 | 2 2 | 1 2 | 2 2 | 2 2 | 2 3 | 1 3 | 2 3 | 2 3 | 2
Это эквивалентно этому запросу, который возвращает те же результаты.
select id, level as lvl
from dual
cross join a
connect by level <= 2
order by id, level
Я не понимаю, почему эти запросы возвращают 12 строк или почему есть три строки, где LVL равен 2 и только один, где LVL равен 1 для каждого значения столбца ID.
увеличение количества уровней, которые "подключены" к 3 возвращает 13 строк для каждого значения ID. 1, где LVL-1, 3, где LVL-2 и 9, где LVL-3. Это, по-видимому, предполагает, что возвращаемые строки - это количество строк в таблице A в степени значения LVL минус 1.
Я бы хотел, чтобы эти запросы были такими же, как следующие, которые возвращают 6 строк
select id, lvl
from ( select level as lvl
from dual
connect by level <= 2
)
cross join a
order by id, lvl
на документация не особенно ясно, для меня, в объяснении того, что должно произойти. Что происходит с этими силами и почему первые два запроса не совпадают с третьим?
4 ответов
в первом запросе вы подключаетесь только по уровню. Поэтому, если уровень
Так для 3 записи:
- 1 лвл: 3 записи (все, имеющие 1 уровень)
- LVL 2: 3 записи, имеющие уровень 1 + 3*3 записи, имеющие уровень 2 = 12
- 3 лвл: 3 + 3*3 + 3*3*3 = 39 (действительно, 13 записей в каждой).
- Lvl 4: начало видеть шаблон? :)
на самом деле это не перекрестное соединение. Перекрестное соединение возвращает только те записи, которые имеют уровень 2 в этом результате запроса, в то время как с этим connect by вы получаете записи, имеющие уровень 1, а также записи, имеющие уровень 2, в результате чего 3 + 3*3 вместо того, чтобы просто 3 * 3 запись.
, когда connect by
используется без start with
п. и prior
оператор, нет никаких ограничений на присоединение дочерней строки к родительской строке. И то, что Oracle делает в этой ситуации, возвращает все возможные перестановки иерархии, подключая строку к каждой строке уровня выше.
SQL> select b
2 , level as lvl
3 , sys_connect_by_path(b, '->') as ph
4 from a
5 connect by level <= 2
6 ;
B LVL PH
---------- ----------
1 1 ->1
1 2 ->1->1
2 2 ->1->2
3 2 ->1->3
2 1 ->2
1 2 ->2->1
2 2 ->2->2
3 2 ->2->3
3 1 ->3
1 2 ->3->1
2 2 ->3->2
3 2 ->3->3
12 rows selected
вы сравниваете яблоки с апельсинами при сравнении окончательного запроса с другими, поскольку уровень изолирован в этой таблице с 1-строчной двойной таблицей.
рассмотрим этот запрос:
select id, level as lvl
from a
connect by level <= 2
order by id, level
что это значит, начните с набора таблиц (выберите * из a). затем для каждой возвращенной строки подключите эту строку к предыдущей строке. поскольку вы не определили соединение в connect by, это фактически Декартовое соединение, поэтому, когда у вас есть 3 строки (1,2,3) 1, присоединяется к 2, 1->3, 2->1, 2 - >3, 3->1 и 3->2 и они также присоединяются к себе 1->1,2->2 и 3 - >3. эти соединения имеют уровень=2. таким образом, у нас есть 9 соединений, поэтому вы получаете 12 строк (3 исходных строки "уровня 1" плюс Декартовый набор).
таким образом, количество выходных строк = rowcount + (rowcount^2)
в последнем запросе вы изолируете уровень
select level as lvl
from dual
connect by level <= 2
что, конечно, возвращает 2 строки. это затем cartesianed в исходные 3 строки, давая 6 строк в качестве вывода.
вы можете использовать технику, чтобы преодолеть эту проблему:
select id, level as lvl
from a
left outer join (select level l from dual connect by level <= 2) lev on 1 = 1
order by id