2017-01-26 2 views
1

Существует таблица articles, включая иерархические структуры articel. 1 сборка состоит из n компонентов. Таким образом, мы можем просматривать структуру и использование (до и ) для статьи.Oracle подключается путем включения критериев останова

Использование Оракулов hierarchical queries Это можно сделать очень эффективно на уровне sql.

SELECT item 
FROM articles 
START WITH component = '0815' 
CONNECT BY NOCYCLE PRIOR assembly = component; 

Представьте себе, что имеется винт с изделием. Этот винт используется во множестве сборок и снова их сборок. Мы хотим выяснить, используется ли ссылка в конкретных сборках, определенных в статье WHERE, несколько уровней выше.

SELECT item 
FROM articles 
WHERE attr1 = 'marker' --any condition 
START WITH component = '0815' 
CONNECT BY NOCYCLE PRIOR assembly = component; 

Это заявление отлично работает, но будет оценивать все возможные сборки в результате. В нашем случае нас просто интересует, если есть хотя бы одна сборка, которая соответствует и не в целом результате. Заявление требует минут для всех сборок, но может быть значительным быстрее, когда оно останавливается после первой строки, чтобы ответить на заданный вопрос.

Есть ли способ сказать Oracle отменить этот запрос после первого совпадения?

+0

Если не так много статей, имеющих 'attr1 =«marker'', почему вы не 'START WITH' те и измените направление своего 'CONNECT BY', чтобы найти винты? –

+0

Спасибо за ваш ответ. Есть '> 4k' сборки для условия' WHERE'. Объект, который я хочу проверить, - это винт. Винт - наихудшая статья. Я хочу ответить на вопрос, существует ли хотя бы одна сборка со специальными значениями атрибутов. Я уверен, что с вашей идеей дерево поиска станет еще больше.И у меня также нет возможности * прервать * запрос в первом матче. – wenzul

+0

По крайней мере, вы можете остановить каждую ветвь, взорванную после первого матча. Вид 'CONNECT BY NOCYCLE PRIOR assembly = component AND PRIOR attr1! = 'Marker'' – Serg

ответ

0

Вы можете использовать Рекурсивный подзапрос факторинга прекратить все поиски, как это:

with h(it,art,match,anymatch) as 
     (select item, assembly 
      ,  case when attr1 = 'marker' then 1 else 0 end 
      , max(case when attr1 = 'marker' then 1 else 0 end) over() 
      from articles 
     where component = '0815' 
     union all 
     select item, assembly 
      ,  case when attr1 = 'marker' then 1 else 0 end 
      , max(case when attr1 = 'marker' then 1 else 0 end) over() 
      from h, articles 
     where art = component 
      and anymatch = 0) 
cycle art set cycle to 1 default 0 
select it item 
    from h 
where match = 1 
    and cycle = 0 

Это возвращает все матчи, которые находятся на минимально возможном уровне.

Однако, поскольку это первый поиск ширины, это будет не намного быстрее, если обнаружено первое найденное .

Смена состояния anymatch = 0 на match = 0 () больше не нужно было бы рассчитывать) остановит только поиск по ветке, в которой находится совпадение.

+0

Спасибо за ваш комментарий. Да 'attr1 = 'marker'' находится на аналогичном глубоком уровне (до 7). – wenzul

+0

@wenzul - Тогда я не понимаю ваш вопрос. Я могу понять, почему, если строка, которую вы ищете, может быть найдена на уровне 2 или 3, вы не хотите, чтобы запрос выполнялся до уровня 7. Но если совпадение действительно будет найдено на уровень 7, то как запрос может занять меньше времени? Вам нужно искать все строки на уровне 2, 3, 4 ... так как вы не знаете, какой конкретный путь приведет вас к вашему матчу. – mathguy

+0

@mathguy Я не понял вашу точку зрения. Я хочу выполнить поиск первой сборки в иерархии * upper * с помощью 'attr1 = ..' и остановить, если я нашел первое событие. Он должен вести себя как поиск по глубине с помощью механизма остановки, если условие поиска совпадает. Реальный случай: если конкретная статья была уже собрана в серии (мнимый attr1), мы должны делать дополнительные вещи во время создания новой редакции статьи. Поэтому для винта я не хочу перечислять все серийные сборки, я просто хочу знать - о, по крайней мере, один раз в серии - заботиться о ревизии. Становится яснее? :) – wenzul

0

Чтобы сделать реальную глубину первого поиска вы можете использовать следующую PL/SQL:

FUNCTION search(p_component IN VARCHAR2, p_attr1 IN VARCHAR2) 
RETURN VARCHAR2 IS 
    i VARCHAR2(4000); 
BEGIN 
    FOR q IN (SELECT * FROM articles WHERE component = p_component) 
    LOOP 
    IF q.attr1 = p_attr1 THEN 
     RETURN q.item; 
    END IF; 
    i := search(q.assembly, p_attr1); 
    IF i IS NOT NULL THEN 
     RETURN i; 
    END IF; 
    END LOOP; 
    RETURN NULL; 
END; 

вызове функции вроде этого:

search('0815', 'marker') 

Я думаю, что это решение будет гораздо медленнее, если не появляется вообще. Он также не проверяет циклы и работает до ограниченного уровня (ограничение для открытых курсоров или стека вызовов может быть исчерпано).

В Oracle 12 вы можете поместить PL/SQL в SQL:

WITH 
    FUNCTION search(p_component IN VARCHAR2, p_attr1 IN VARCHAR2) 
    RETURN VARCHAR2 IS 
    i VARCHAR2(4000); 
    BEGIN 
    FOR q IN (SELECT * FROM articles WHERE component = p_component) 
    LOOP 
     IF q.attr1 = p_attr1 THEN 
     RETURN q.item; 
     END IF; 
     i := search(q.assembly, p_attr1); 
     IF i IS NOT NULL THEN 
     RETURN i; 
     END IF; 
    END LOOP; 
    RETURN NULL; 
    END; 
SELECT search('0815', 'marker') 
    FROM dual 
+0

Благодарим вас за второй ответ. PL/SQL был бы моим последним выбором. Я хочу сохранить locig в приложении из-за причин обслуживания, таких как развертывание. В статье '0815' нет' attr1 = 'marker''. Маркер существует на другом уровне. '0815' - это только стартовая статья ... – wenzul

Смежные вопросы