|
Как работать с рекурсиями в ХП? Киньте примером!
|
|||
---|---|---|---|
#18+
НАДО НАПОЛНИТЬ РЕКОРДСЕТ В РЕКУРСИИ ... |
|||
:
Нравится:
Не нравится:
|
|||
29.03.2001, 16:28 |
|
Как работать с рекурсиями в ХП? Киньте примером!
|
|||
---|---|---|---|
#18+
А может не стоит? Написать то не сложно create procedure #r @i int as declare @ii int if @i<0 return select @i select @ii=@i-1 exec #r @ii go exec #r 20 Но глубина вложенности небольшая - 32 всего(попробуйте exec #r 40 ), да и как-то ненадежно оно работает. С рекурсией оно конечно выглядит красиво, но без неё всегда можно обойтись. ... |
|||
:
Нравится:
Не нравится:
|
|||
29.03.2001, 16:56 |
|
Как работать с рекурсиями в ХП? Киньте примером!
|
|||
---|---|---|---|
#18+
> С рекурсией оно конечно выглядит красиво, но без неё всегда можно обойтись. Прямо-таки всегда? Дано: Create table T (ID int primary key, Name varchar(50), Parent_ID int) Смысл, думаю, понятен. Таблица для хранения дерева. Нужно обеспечить удаление всех дочерних, внучатых, правнучатых... и т.д. записей при удалении узлов дерева. Вариант 1. Заранее известно, что глубина дерева не превышает ограничения по вложенности рекурсивных триггеров (16 для 7.0) Тогда, IMHO, самое правильное решение написать рекурсивный триггер: create trigger T_OnDel on T as if exists(select T.ID from T, deleted D where T.Parent_ID=D.ID) Delete from T from T, deleted D where T.Parent_ID=D.ID Это и изящно, и вообще... Вариант 2. Заранее известно, что глубина дерева не превышает ограничения по вложенности хранимых процедур (32 для 7.0). Триггер делается нерекурсивным. Но он вызывает хранимую процедуру, которая рекурсивна (текст писать не буду - интуитивно ясно). Вариант 3. Глубина дерева вообще не ограничена. Увы, алгоритм раскраски дерева по своей природе рекурсивен. Рекурсия организуется с помощью стека. Выкручиваться, естественно придется без рекурсивных возможностей инструментария, поскольку уперлись в ограничения MS SQL Server. Делается все на циклах, но геморройно, поскольку нужно что-то вроде стека организовать самому (временная таблица). Должен оговориться, что для варианта 3 есть нерекурсивный по природе вариант на голом цикле. На первом шаге цикла во временную таблицу переписываются ID и Parent_ID удаляемых записей (которую подали с клиента). На каждом следующем шаге цикла в эту таблицу переписываются ID и Parent_ID записей, которых пока что нет в этой таблице, но Paraent_ID которых in (select ID from #TemTable). И так до тех пор, пока переписывать будет нечего. В #TempTable получаем набор швутеификаторов всех записей, которые необходимо удалить - выдаем одну-единственную команду Delete - и всё. Да, алгоритм не рекурсивный. Но он еще и не оптимальный. Поскольку на каждом шаге цикла в перечень просматриваемых записей попадают те, которые уже раньше просмотрены (ID записей из верхних уровней дерева), и повторно просматривать которые нет смысла - а это дополнительный тормоз. ... |
|||
:
Нравится:
Не нравится:
|
|||
29.03.2001, 21:08 |
|
Как работать с рекурсиями в ХП? Киньте примером!
|
|||
---|---|---|---|
#18+
"на каждом шаге цикла в перечень просматриваемых записей попадают те, которые уже раньше просмотрены (ID записей из верхних уровней дерева), и повторно просматривать которые нет смысла - а это дополнительный тормоз." Ну если не устраивает именно это, то ведь моно иметь еще одну промежуточную таблицу, которая будет содержать ID записей, которые были добавлены в #TemTable непосредственно на предыдущем шаге... Ну а собсно инсертить их в #TemTable после того как они больше не нужны и делать в конце один большой Delete или Delete-ать их сразу- как больше нравится ... |
|||
:
Нравится:
Не нравится:
|
|||
30.03.2001, 00:27 |
|
Как работать с рекурсиями в ХП? Киньте примером!
|
|||
---|---|---|---|
#18+
2 Garya В принципе я согласен. Но не стоит хранить данные так, чтобы это предполагало рекурсивную обработку. Наверняка вы это читали: http://sdm.viptop.ru/articles/sqltrees.html ... |
|||
:
Нравится:
Не нравится:
|
|||
30.03.2001, 10:00 |
|
Как работать с рекурсиями в ХП? Киньте примером!
|
|||
---|---|---|---|
#18+
Этот вопрос уже много раз обсуждался. Ваш Вариант 3 с временной таблицой - самый оптимальный. На любой большой СУБД при больших объёмах данных он будет работать не в разы, а на порядки быстрее - секунды или минуты вместо часов или дней. Это следует из принципов организации БД - выполнить немного больших стейтментов (по к-ву уровней дерева) намного легче, чем много маленьких (по к-ву строк - миллион?). Конечно, что-бы не было "каждом шаге цикла в перечень просматриваемых записей попадают те..." нужно в упомянутую временную таблицу добавить поле Level и включить его в условие. Надо привыкнуть, что рекурсия в SQL - самый "неизящный" метод программирования, это наследие процедурно-объектного мышления: SQL - не С или С++. ... |
|||
:
Нравится:
Не нравится:
|
|||
30.03.2001, 18:08 |
|
Как работать с рекурсиями в ХП? Киньте примером!
|
|||
---|---|---|---|
#18+
Честно говоря, не знаю как именно в SQL Server рекурсивность сказывается на быстродействии. Во всех остальных инструментариях отрицательно. Это связано с необходимостью сохранения в стеке всех локальных переменных. Возможно, в SQL ситуация не просто аналогичная, но соображения alexeyvg являются дополнительным и более важным фактором, сказывающимся на быстродействии. Тем не менее, не могу согласиться с тем, что рекусия - самый неизящный стиль. IMHO, как раз наоборот. Посмотри на текст рекурсивного триггера (в 2 строчки) и сравни с текстом аналогичного нерекурсивного скрипта. В этом плане я скорее соглашусь со мнением SergSuper. По поводу того, что рекурсия - это наследие процедурного мышления (в смысле "пережиток") тоже не могу согласиться. Современный Transact-SQL содержит операторы Exec (аналог Call), If, While, механизмы пошаговых вычислений, локальные переменные. Это все атрибуты процедурного программирования. И появились они не в первых версиях T-SQL с последующим отмиранием, а наоборот. Даже термин "stored procedure" говорит сам за себя (а не "stored query"). И это не пережиток, а веление времени. Грани между процедурным языком и языком запросов постепенно стираются. В версиях 7.0 и 2000 SQL-сервера получило развитие обращение объектам БД в контексте объектной модели (родитель.объект-свойство). Я не удивлюсь, если в будущем увижу диалекты T-SQL, поддерживающие множественное наследие и перегрузку операций. IMHO, поезд катится не просто к процедурному, а еще и к объектно-ориентированному. Это неизбежный процесс, если речь идет о переносе бизнес-логики на сервер. Отказавшись от процедурного мышления, далеко не все можно реализовать операциями базовой реляционной алгебры. Также не могу согласиться, что реляционное мышление - это пик человеческой мысли. Графы, деревья продолжают использоваться вместе с табличными представлениями и отмирать не собираются. Когда-то на MUMPS (иерархическая СУБД) программисты ломали голову над тем, как выполнять агрегатные функции и произвольно задаваемые объединения по таблично-подобным данным. Теперь более молодое поколение ломает голову над тем, как с помощью табличных структур представить граф или дерево так, чтобы с ним было удобно работать методами реляционной алгебры. Я уверен, что следующее поколение сможет работать и стем, и с другим с одинаковой легкостью, получив настоящий объектно-ориентированный инструментарий. ... |
|||
:
Нравится:
Не нравится:
|
|||
30.03.2001, 18:53 |
|
|
start [/forum/topic.php?fid=46&tid=1827090]: |
0ms |
get settings: |
10ms |
get forum list: |
14ms |
check forum access: |
4ms |
check topic access: |
4ms |
track hit: |
41ms |
get topic data: |
13ms |
get forum data: |
3ms |
get page messages: |
50ms |
get tp. blocked users: |
2ms |
others: | 13ms |
total: | 154ms |
0 / 0 |