Oracle SQL начинается с/до

Мне удалось понять, как работает подключение по уровням, в приведенном ниже примере:

SELECT
    level,
    t.*
FROM
    (
        SELECT
            'a' AS col1,
            'b' AS col2
        FROM
            dual
        UNION ALL
        SELECT
            'c',
            'd'
        FROM
            dual
    ) t
CONNECT BY
    level <= 3

Тем не менее, я изо всех сил пытаюсь понять концепции «начать с» и «до» и какие варианты использования они имеют в реальной жизни. Может кто-нибудь, пожалуйста, помогите мне, используя предоставленный пример?


person Javi Torre    schedule 20.03.2021    source источник
comment
Обзор Тома Кайта связан. Иерархические запросы являются лучшим примером. Сотрудники и их руководители. asktom.oracle.com/pls /вершина/   -  person Brian    schedule 20.03.2021
comment
Строка (a, b) не имеет отношения родитель/потомок к строке (b, c). Будет проще продемонстрировать работу с иерархиями с иерархическими данными, чем просто использовать connect by (не обязательно connect by level - лично я предпочитаю connect by rownum) в качестве хака генерации строк.   -  person William Robertson    schedule 20.03.2021
comment
@WilliamRobertson, в чем разница между подключением по уровню и по номеру строки?   -  person Javi Torre    schedule 20.03.2021
comment
Это не совсем соединение по уровню. Синтаксис: connect by, за которым следует выражение, которое вычисляется для каждой итерации. (В документации указано, что ключевое слово prior является обязательным, хотя это не применяется, поэтому это иногда рассматривается как хак.) rownum <= 3 верно для первых трех строк, поэтому вы получите 3 строки обратно. level <= 3 верно для первых трех уровней, что зависит от набора, с которого вы начинаете. Поскольку вы начинаете с более чем одной строки и просите ее сгенерировать все иерархии для каждой строки, вы получите обратно экспоненциальное количество строк.   -  person William Robertson    schedule 20.03.2021
comment
@WilliamRobertson, если я заменю в запросе моего вопроса слово «уровень» словом «rownum», он вернет 4 строки. Почему это?   -  person Javi Torre    schedule 20.03.2021
comment
Я не уверен, если честно. Он генерирует 3 строки для col1 = a и еще одну для b. Обычно, когда мы используем connect by без условия prior или start with, мы используем его для генерации нескольких строк из 1 строки в двойном режиме, и нет никакого смысла основывать его на многострочном наборе, поскольку вы получаете эту бессмысленную экспоненциальную результат. Действительно, start with и prior и есть вся суть connect by, и использовать его без них в качестве генератора строк — хак, хоть и удобный.   -  person William Robertson    schedule 21.03.2021


Ответы (1)


Если у вас отношения родитель/ребенок:

CREATE TABLE t ( parent, child ) AS
  SELECT 'a', 'b' FROM dual UNION ALL
  SELECT 'b', 'c' FROM dual UNION ALL
  SELECT 'c', 'd' FROM dual UNION ALL
  SELECT 'd', 'e' FROM dual;

И вы хотите получить генеалогическое древо, начиная с b, и получить всех потомков, тогда вы можете:

SELECT level,
       t.*
FROM   t
START WITH parent = 'b'
CONNECT BY PRIOR child = parent

Что выводит:

LEVEL | PARENT | CHILD
----: | :----- | :----
    1 | b      | c    
    2 | c      | d    
    3 | d      | e    

Уровень 1 начинается с b, затем уровень 2 имеет дочерний элемент b c, затем уровень 3 имеет дочерний элемент (внук) d ребенка b, и все они связаны отношением, согласно которому PRIOR child является (текущим) parent.

Дополнительные примеры того, как получить различные отношения, можно найти в этом ответе.


Кроме того, ваш пример в вопросе немного сбивает с толку, поскольку он находит все пути на глубину 3 рекурсии. Если вы покажете пути, которые он прошел через данные, используя SYS_CONNECT_BY_PATH, тогда вы получите лучшее представление:

SELECT level,
       t.*,
       SYS_CONNECT_BY_PATH( '('||col1||','||col2||')', '->' ) AS path
FROM (
  SELECT 'a' AS col1, 'b' AS col2 FROM dual UNION ALL
  SELECT 'c', 'd' FROM dual
) t
CONNECT BY level <= 3

Что выводит:

LEVEL | COL1 | COL2 | PATH                 
----: | :--- | :--- | :--------------------
    1 | a    | b    | ->(a,b)              
    2 | a    | b    | ->(a,b)->(a,b)       
    3 | a    | b    | ->(a,b)->(a,b)->(a,b)
    3 | c    | d    | ->(a,b)->(a,b)->(c,d)
    2 | c    | d    | ->(a,b)->(c,d)       
    3 | a    | b    | ->(a,b)->(c,d)->(a,b)
    3 | c    | d    | ->(a,b)->(c,d)->(c,d)
    1 | c    | d    | ->(c,d)              
    2 | a    | b    | ->(c,d)->(a,b)       
    3 | a    | b    | ->(c,d)->(a,b)->(a,b)
    3 | c    | d    | ->(c,d)->(a,b)->(c,d)
    2 | c    | d    | ->(c,d)->(c,d)       
    3 | a    | b    | ->(c,d)->(c,d)->(a,b)
    3 | c    | d    | ->(c,d)->(c,d)->(c,d)

Вы получаете 14 строк, потому что вы получаете 2 строки на уровне 1 (по одной для каждой комбинации входных строк), а затем 4 строки на уровне 2 (по одной для каждой входной строки для каждой строки уровня 1), а затем 8 строк на уровне 2 (по одной для каждой строки ввода). каждая входная строка для каждой строки уровня 2), и ваши выходные данные растут в геометрической прогрессии.

db‹›fiddle здесь

person MT0    schedule 20.03.2021