2017-01-11 2 views
1

Oracle Database 12c Enterprise Edition Release 12.1.0.2.0Oracle Connect По-видимому, дает слишком много строк

Я ожидаю, что я просто что-то отсутствует, но если я запускаю этот запрос без «подключения по», я получите 2 строки. Когда я добавляю «connect by level < = 4», я бы ожидал получить каждый из этих 2 строк 4 раза. Фактический результат отличается.

Может ли кто-нибудь помочь мне понять, что здесь происходит? Я не ищу решение, которое только повторяет каждую строку 4 раза - я уже получил это. Я просто хочу понять, что происходит и почему.

with alpha as (
     select 1 as id 
      from dual 
    ), 
    beta as (
     select 1 as alpha_id, 
       1 as beta_no 
      from dual 
     union all 
     select 1 as alpha_id, 
       2 as beta_no 
      from dual 
    ) 
select a.id, 
     b.beta_no, 
     level as the_level 
    from alpha a 
     inner join beta b 
      on b.alpha_id = a.id 
    connect by level <= 4 
    order by a.id, 
     b.beta_no, 
     level 
; 
ID BETA_NO THE_LEVEL 

 1   1   1 
    1   1   2 
    1   1   2 
    1   1   3 
    1   1   3 
    1   1   3 
    1   1   3 
    1   1   4 
    1   1   4 
    1   1   4 
    1   1   4 
    1   1   4 
    1   1   4 
    1   1   4 
    1   1   4 
    1   2   1 
    1   2   2 
    1   2   2 
    1   2   3 
    1   2   3 
    1   2   3 
    1   2   3 
    1   2   4 
    1   2   4 
    1   2   4 
    1   2   4 
    1   2   4 
    1   2   4 
    1   2   4 
    1   2   4 

30 строк выбран

Большое спасибо mathguy. Вторая ссылка, которую он привел в приведенном ниже ответе, имела именно то, что я искал. В частности:

1 with t as (select 1 as id from dual union all 
    2    select 2 from dual) 
    3 -- 
    4 select id, level 
    5  ,prior id 
    6  ,sys_connect_by_path(id,'=>') as cpath 
    7 from t 
    8* connect by level <= 3 
SQL>/

     ID  LEVEL PRIORID CPATH 
---------- ---------- ---------- -------------------------------------------------- 
     1   1   =>1 
     1   2   1 =>1=>1 
     1   3   1 =>1=>1=>1 
     2   3   1 =>1=>1=>2 
     2   2   1 =>1=>2 
     1   3   2 =>1=>2=>1 
     2   3   2 =>1=>2=>2 
     2   1   =>2 
     1   2   2 =>2=>1 
     1   3   1 =>2=>1=>1 
     2   3   1 =>2=>1=>2 
     2   2   2 =>2=>2 
     1   3   2 =>2=>2=>1 
     2   3   2 =>2=>2=>2 

14 rows selected. 

Это для меня ясно из этого примера, но я бы с трудом решился кратко выразить словами.

ответ

2

Без каких-либо условий, кроме «уровня < = 4», каждая строка из исходной таблицы, вида и т. Д. (От объединения в этом случае) будет производить две строки на уровне 2, затем еще четыре строки на уровне 3 , и еще 8 на уровне 4. «Подключиться» - это, по сути, последовательность объединений, и вы выполняете кросс-соединения, если у вас нет условий с оператором ПРИОР.

Возможно, вы захотите добавить «и ранее a.id = a.id». Это приведет к тому, что Oracle будет жаловаться на циклы (поскольку Oracle решает, что цикл достигается, когда он видит те же значения в столбцах, на которые распространяется PRIOR). Это, в свою очередь, решается добавлением третьего условия, обычно «и предыдущий sys_guid() не является нулевым».

(ред, оригинальный ответ сделал ссылку на NOCYCLE, который не требуется при использовании «предварительного SYS_GUID() не является нулевой» подход.)

Это обсуждалось в последнее время на OTN: https://community.oracle.com/thread/3999985

Тот же вопрос обсуждался здесь: https://community.oracle.com/thread/2526535

+1

@Boneist - Правильно! Я отредактирую, чтобы уточнить. Благодаря! – mathguy

+0

Спасибо mathguy и Boneist. Как я уже сказал, я не ищу исправления, я просто пытаюсь понять, что вызывает его. Я думаю, что я поиграю с подключением по пути и посмотрю, смогу ли я это выяснить ... –

+0

@MattKnowles - я не предлагал это в качестве исправления вашего запроса - я предложил это (часть) объяснения из того, что вы видели.Если вы будете следовать ссылкам и дальнейшим ссылкам оттуда, вы увидите, что обсуждение в значительной степени касается «как это работает», а не «как оно используется для решения конкретной проблемы». Игра с ним сама, как вы планируете сделать, также очень поможет. Удачи! – mathguy

0

Чтобы проиллюстрировать ответ Mathguy, вы не хватаете некоторые предикаты из вашего CONNECT BY предложения:

with alpha as (
     select 1 as id 
      from dual 
    ), 
    beta as (
     select 1 as alpha_id, 
       1 as beta_no 
      from dual 
     union all 
     select 1 as alpha_id, 
       2 as beta_no 
      from dual 
    ) 
select a.id, 
     b.beta_no, 
     level as the_level 
from alpha a 
     inner join beta b 
     on b.alpha_id = a.id 
connect by level <= 4 
      AND PRIOR a.id = a.id 
      AND PRIOR b.beta_no = b.beta_no 
      AND PRIOR sys_guid() IS NOT NULL 
order by a.id, 
     b.beta_no, 
     LEVEL; 

     ID BETA_NO THE_LEVEL 
---------- ---------- ---------- 
     1   1   1 
     1   1   2 
     1   1   3 
     1   1   4 
     1   2   1 
     1   2   2 
     1   2   3 
     1   2   4 

В качестве альтернативы можно использовать рекурсивный с пунктом:

with alpha as (
     select 1 as id 
      from dual 
    ), 
    beta as (
     select 1 as alpha_id, 
       1 as beta_no 
      from dual 
     union all 
     select 1 as alpha_id, 
       2 as beta_no 
      from dual 
    ), 
    multiply (id, beta_no, rn) AS (SELECT a.id, 
              b.beta_no, 
              1 rn 
            FROM alpha a 
              INNER JOIN beta b 
              ON a.id = b.alpha_id 
            UNION ALL 
            SELECT ID, 
              beta_no, 
              rn + 1 
            FROM multiply 
            WHERE rn + 1 <= 4) 
SELECT ID, 
     beta_no, 
     rn AS the_level 
FROM multiply 
order by id, 
     beta_no, 
     rn; 

     ID BETA_NO THE_LEVEL 
---------- ---------- ---------- 
     1   1   1 
     1   1   2 
     1   1   3 
     1   1   4 
     1   2   1 
     1   2   2 
     1   2   3 
     1   2   4 
Смежные вопросы