|
|
|
Рекурсия и Хранимая процедура
|
|||
|---|---|---|---|
|
#18+
Существует таблица FILES вида Код: plaintext 1. 2. 3. 4. 5. 6. 7. 8. 9. 10. 11. 12. 13. описывающая дерево каталогов на диске С: C:\DOS\config.sys C:\DOS\himem.sys C:\DOC\SUBDOC\s1.doc C:\DOC\SUBDOC\s2.doc C:\DOC\1.txt C:\DOC\2.txt C:\MSDOS.SYS C:\COMMAND.COM ParentId и PreviousId левыми джойнами связаны с NodeId. Такое хранение удобно и построением дерева и для добавления узлов к любой ноде, и удаления любых нод, при этом если ноды содержат чилдренов, они удаляются каскадным удалением. Поэтому менять структуру таблицы ради решения задачи не хочется. Проблема в подсчете объема файлов в заданном каталоге - например DOC. Обход любого дерева проще всего сделать используя рекурсию, но хочется использовать хранимую процедуру. Помогите сделать хранимую процедуру, которая будет возвращать объем файлов (всех с подкаталогами). У меня получилось что-то типа: Код: plaintext 1. 2. 3. 4. 5. 6. 7. 8. 9. 10. 11. 12. 13. 14. 15. 16. 17. 18. 19. 20. 21. 22. 23. 24. Бред, конечно, но какие еще есть варианты? Pls! ... |
|||
|
:
Нравится:
Не нравится:
|
|||
| 20.11.2002, 16:46:19 |
|
||
|
Рекурсия и Хранимая процедура
|
|||
|---|---|---|---|
|
#18+
Так у тебя точно ничего не получится, так как, насколько я понимаю, курсор вещь глобальная, и если ты его открываешь, а потом входишь в рекурсию, то ты внутри рекурсии открыть курсор не сможешь, так как он уже был однажды открыт (проверено). Более того, когда ты сделаешь FETCH внутри рекурсии, то получишь из курсора то значение, которое ты получил бы из своей функции GetSize самого высокого уровня. Вот если бы курсоры были типа локальных переменных - тогда другой вопрос. Можно попробовать сделать это через рекурсивные триггеры, правда, они имеют ограничение на глубину рекурсии 32, но этого должно хватить. К примеру, нужно посчитать обьем каталога DOC: Для этого нужно Создать глобальную переменную AllSize и UPDATE_FLAG. В опциях базы данных включить рекурсивные триггеры. Создать процедуру GetSize: CREATE PROCEDURE GetSize AS // UPDATE_FLAG - некоторая созд. тобой глоб. перем // показывающая, что приложение в режиме подсчета SET @@UPDATE_FLAG = 1 SET @@allsize = 0 DELETE FILES WHERE NodeName = 'DOC' SET @@UPDATE_FLAG = 0 GO Создать триггер на обновление. CREATE TRIGGER tU_Files ON Files FOR UPDATE AS BEGIN IF(@@UPDATE_FLAG=1) BEGIN IF (SELECT Count(NodeID) FROM Deleted) <> 0 BEGIN SELECT @@allsize = @@allsize + (SELECT Sum(F1.size) FROM FILES WHERE Files.ParentID = ANY (SELECT NodeID FROM Deleted) DELETE FROM Files WHERE Files.ParentID = ANY (SELECT NodeID FROM Deleted) AND Files.Node_Type = "Folder" END; INSERT INTO Files FROM Deleted END; END; Суть в чем: Ты удаляешь каталог, который хочешь подсчитать, в триггере на удаление ты считываешь ID удаленного каталога, К переменной allsize добавляешь обьем всех дочерних файлов, и удаляешь все дочерние каталоги. Для всех удаленных каталогов ты подсчитываешь обьем всех дочерних файлов и удаляешь все дочерние для удаленных каталоги. И т.д. до каталогов вложенности 32 максимум (тебе должно хватить с головой). При завершении триггеров все удаленные каталоги восстановлятся. Данные не пропадут, так как все выполняется в контексте одной транзакции ... |
|||
|
:
Нравится:
Не нравится:
|
|||
| 20.11.2002, 20:08:57 |
|
||
|
Рекурсия и Хранимая процедура
|
|||
|---|---|---|---|
|
#18+
Если SQL2000, то можно создать пару рекурсивных функций, с помощью которых это решается. Если интересует, то завтра подробно расскажу. ... |
|||
|
:
Нравится:
Не нравится:
|
|||
| 20.11.2002, 20:20:27 |
|
||
|
Рекурсия и Хранимая процедура
|
|||
|---|---|---|---|
|
#18+
Re VVG_. Спасибо, подожду до завтра. ... |
|||
|
:
Нравится:
Не нравится:
|
|||
| 20.11.2002, 21:02:50 |
|
||
|
Рекурсия и Хранимая процедура
|
|||
|---|---|---|---|
|
#18+
Re Vetal: Идея неплоха, я ее потестирую, но: - во-первых, глубина рекурсии 32 - очень мала, это в данном примере, для понимания сути приведены файлы в каталогах, но в реальной базе глубина дерева достигает нескольких сотен, единиц тысяч... - во-вторых, не очень понятно с удалением, если транзакция не завершается, то физического удаления не происходит, и, можно считать, что на времени выполнения это не сказывается? Если на рекурсии накладываются такие ограчничения, можно ли в такой таблице обойтись без рекурсии? ... |
|||
|
:
Нравится:
Не нравится:
|
|||
| 20.11.2002, 21:13:28 |
|
||
|
Рекурсия и Хранимая процедура
|
|||
|---|---|---|---|
|
#18+
PreviousId - бред сивой кобылы, ошибка дизайна. Ну да ладно, это маловажная вещь. Но зачем вам понадобилось строить дерево неопределенной глубины на реляционной базе и делать обработку на сервере - вот этого уже я никак понять не могу. Сама концепция реляционной базы предотвращяет ее использование для древовидных данных. Обрабатывайте деревья на клиенте и будет вам радость. Сервер закопается стопудово, особенно если вы увлечетесь курсорами. ... |
|||
|
:
Нравится:
Не нравится:
|
|||
| 20.11.2002, 21:50:19 |
|
||
|
Рекурсия и Хранимая процедура
|
|||
|---|---|---|---|
|
#18+
Re: Gobzo Kobler Дело в том, что дерево с кучей узлов и неопределенной глубины - это всего одна таблица - основа базы. К каждой ноде привязано куча таблиц и данных в них именно реляционных. Там уже тысячи запросов, сотни мегабайт данных, поэтому переделывать эту таблицу не хочу. С такой структурой таблицы (ParentID, PreviousID) методами FirstChild и Next в рекурсии на контроле строится дерево и поддержаны куча методов по движению нод, и т.д. и т.п, а зная NodeId, основная работа ведется с недревовидной частью базы. Но это уже тема отдельного разговора. Вернемся к баранам, может можно обойтись без рекурсии? ... |
|||
|
:
Нравится:
Не нравится:
|
|||
| 20.11.2002, 23:06:08 |
|
||
|
Рекурсия и Хранимая процедура
|
|||
|---|---|---|---|
|
#18+
Re Chainiko Вообще-то ограничение на глубину рекурсии насколько я знаю, накладывается только на триггеры. Если все написать как-то через хранимые процедуры, то там таких ограничений вроде как нет. Что касается того, что данные не удаляются, то ведь они же и не должны удаляться, информация должна только подсчитываться. А на производительность это конечно же влияет, так как время на выполнение кода в триггере все-равно тратится. Если же ты все это хочешь сделать на стороне сервера, то напиши расширенную хранимую процедуру (extended sp), в ней ты можешь воспользоваться функиями языка C, и эта процедура будет выполняться на сервере. ... |
|||
|
:
Нравится:
Не нравится:
|
|||
| 21.11.2002, 00:46:28 |
|
||
|
Рекурсия и Хранимая процедура
|
|||
|---|---|---|---|
|
#18+
Если циклов нет, то будет работать Код: plaintext 1. 2. 3. 4. 5. 6. 7. 8. 9. 10. 11. 12. 13. 14. 15. 16. 17. 18. 19. 20. 21. 22. 23. 24. 25. 26. 27. 28. 29. 30. 31. 32. 33. 34. 35. 36. 37. 38. 39. 40. 41. 42. 43. 44. 45. 46. 47. 48. 49. 50. 51. 52. 53. 54. 55. 56. 57. 58. 59. 60. 61. 62. ... |
|||
|
:
Нравится:
Не нравится:
|
|||
| 21.11.2002, 09:10:11 |
|
||
|
Рекурсия и Хранимая процедура
|
|||
|---|---|---|---|
|
#18+
Вот вариант в функциями: Код: plaintext 1. 2. 3. 4. 5. 6. 7. 8. 9. 10. 11. 12. 13. 14. 15. 16. 17. 18. 19. 20. 21. 22. 23. 24. 25. 26. 27. 28. 29. 30. 31. 32. 33. 34. 35. 36. 37. 38. 39. 40. 41. 42. 43. 44. 45. ... |
|||
|
:
Нравится:
Не нравится:
|
|||
| 21.11.2002, 11:17:09 |
|
||
|
Рекурсия и Хранимая процедура
|
|||
|---|---|---|---|
|
#18+
Мой предыдущий вариант лобовой и, следовательно, не слишком оптимальный. А вот более прогрессивное решение. Код: plaintext 1. 2. 3. 4. 5. 6. 7. 8. 9. 10. 11. 12. 13. 14. 15. 16. 17. 18. 19. 20. 21. 22. 23. 24. 25. 26. 27. 28. 29. 30. 31. 32. 33. 34. 35. 36. 37. 38. 39. 40. 41. 42. 43. 44. 45. 46. 47. 48. 49. 50. 51. 52. 53. 54. 55. ЗЫ. Итерация свойственна человеку, рекурсия - божественна ... |
|||
|
:
Нравится:
Не нравится:
|
|||
| 21.11.2002, 11:44:58 |
|
||
|
Рекурсия и Хранимая процедура
|
|||
|---|---|---|---|
|
#18+
интересное решение Древовидные структуры в SQL ... |
|||
|
:
Нравится:
Не нравится:
|
|||
| 21.11.2002, 12:06:13 |
|
||
|
Рекурсия и Хранимая процедура
|
|||
|---|---|---|---|
|
#18+
Мой модифицированный вариант. Вместо триггеров теперь рекурсивно вызываются процедуры, и, соответственно, нет ограничения 32. CREATE TABLE #TmpFilesTable(NodeID integer) go // Добавляем во временную таблицу ID папки Docs // размер которой нужно подсчитать INSERT INTO #TmpFilesTable VALUES(5); GO SET @@AllSize = 0 GO CREATE PROCEDURE GETSIZE AS BEGIN IF (SELECT Count(NodeID) FROM #TmpFilesTable) <> 0 BEGIN SELECT @@allsize = @@allsize + (SELECT Sum(Files.size) FROM FILES WHERE Files.ParentID = ANY (SELECT NodeID FROM #TmpFilesTable) DELETE FROM #TmpFilesTable INSERT INTO #TmpFilesTable VALUES (SELECT NodeID FROM FILES WHERE Files.ParentID = ANY (SELECT NodeID FROM #TmpFilesTable)) EXEC GETSIZE; END; END; go DELETE TABLE #TmpFilesTable Можешь переменную AllSize использовать как возвращаемый параметр функции, а не как глобальную переменную ... |
|||
|
:
Нравится:
Не нравится:
|
|||
| 21.11.2002, 15:05:30 |
|
||
|
Рекурсия и Хранимая процедура
|
|||
|---|---|---|---|
|
#18+
2Vetal: Вместо триггеров теперь рекурсивно вызываются процедуры, и, соответственно, нет ограничения 32. Смотрим BOL, раздел SQL Server Architecture / Implementation Details / Maximum Capacity Specifications. Видим Nested stored procedure levels = 32 Nested trigger levels = 32 No comments ... |
|||
|
:
Нравится:
Не нравится:
|
|||
| 21.11.2002, 15:21:00 |
|
||
|
Рекурсия и Хранимая процедура
|
|||
|---|---|---|---|
|
#18+
2 VVG: Ваша функция не работает. Вставляем в соответствующем месте вашего скрипта Код: plaintext 1. 2. 3. 4. 5. 6. 7. 8. 9. 10. 11. 12. 13. 14. 15. 16. 17. 18. 19. 20. 21. 22. 23. 24. 25. 26. 27. 28. 29. 30. 31. 32. 33. 34. 35. 36. 37. и на прогоне получаем Server: Msg 217, Level 16, State 1, Procedure udf_Nodes, Line 10 Maximum stored procedure, function, trigger, or view nesting level exceeded (limit 32). Вот так. На UDF ограничение вложенности распространяется. ... |
|||
|
:
Нравится:
Не нравится:
|
|||
| 21.11.2002, 15:48:21 |
|
||
|
Рекурсия и Хранимая процедура
|
|||
|---|---|---|---|
|
#18+
Млин, отвоевал ты свой вариант, отвоевал. Но иметь 32 уровня вложенности папок на диске - это перебор. ... |
|||
|
:
Нравится:
Не нравится:
|
|||
| 21.11.2002, 15:53:15 |
|
||
|
Рекурсия и Хранимая процедура
|
|||
|---|---|---|---|
|
#18+
Да, господа, много я проспал. Пока выяснялось, что на ХП тоже есть ограничение на рекурсию я слепил кусок кода, работающего на Visual Basic. Не хочу использовать триггер, может кто-нибудь поможет банально транслировать код в ХП? Я не очень владею синтаксисом ХП, но чем мне нравится этот вариант, так это отсутствием создания временных таблиц. Осталось лишь оформить ХП. Мне не очень понятно, что будет с @nodeID в первом запросе, если он вернет 0 записей? NULL? 0? Или она вообще не проинициализируется? На что ее проверять? И как звучит exit PROCEDURE на диалекте ХП? Код: plaintext 1. 2. 3. 4. 5. 6. 7. 8. 9. 10. 11. 12. 13. 14. 15. 16. 17. 18. 19. 20. 21. 22. 23. 24. 25. 26. 27. 28. 29. 30. 31. 32. 33. 34. 35. 36. 37. 38. 39. 40. 41. ЗЫ. На используемого провайдера просьба бочку не катить, это так, для тестов. ... |
|||
|
:
Нравится:
Не нравится:
|
|||
| 22.11.2002, 00:36:44 |
|
||
|
Рекурсия и Хранимая процедура
|
|||
|---|---|---|---|
|
#18+
2 Chainiko: Не-е-е, сам транслируй свой VB в T-SQL. Скажу честно, на твоей задаче мы вчера классно оттянулись, написали то, что считали нужным написать в данном случае и писать по другому нам банально не интересно. Плохо знаешь синтаксис T-SQL? Ну вот и замечательно! Отличный повод потренироваться!!! В ветке полно интересных примеров. Их можно использовать как источник вдохновения. return procedure -> return [<return value>] Я тоже не знаю чему будет равен @nodeid, если запрос не вернет записей. В документации этот вопрос слабо освещен. Поэтому я бы вообще не делал на этот счет никаких предположений. Сегодня так, а в MS SQL Server XP 2010 может быть по другому. Зато точно известно, что если запрос не вернет записей, то сразу после его завершения переменная @@rowcount будет равна 0. В нашем случае это все, что нужно. P.S. Не следует обижаться, но VB вам тоже нужно подучить. ... |
|||
|
:
Нравится:
Не нравится:
|
|||
| 22.11.2002, 07:51:37 |
|
||
|
Рекурсия и Хранимая процедура
|
|||
|---|---|---|---|
|
#18+
Тут вроде код sp просили, предлагаю свой вариант. Код: plaintext 1. 2. 3. 4. 5. 6. 7. 8. 9. 10. 11. 12. 13. 14. 15. 16. 17. 18. ... |
|||
|
:
Нравится:
Не нравится:
|
|||
| 22.11.2002, 08:36:18 |
|
||
|
Рекурсия и Хранимая процедура
|
|||
|---|---|---|---|
|
#18+
Re Chicago: P.S. Не следует обижаться, но VB вам тоже нужно подучить. Если Вас не затруднит, не укажете ли на ошибки, это конечно не VB форум, но если уж А, то и Б нужно говорить. Мне это только на пользу пойдет. ... |
|||
|
:
Нравится:
Не нравится:
|
|||
| 23.11.2002, 01:23:43 |
|
||
|
Рекурсия и Хранимая процедура
|
|||
|---|---|---|---|
|
#18+
Re: Flint-San Очень понравилась Ваша процедура. Коротко и со вкусом. Только нихрена не понятно как работает! Не могди бы объяснить Чайнику, коротко, в двух-трех словах? Заранее благодарю. ... |
|||
|
:
Нравится:
Не нравится:
|
|||
| 23.11.2002, 01:27:21 |
|
||
|
Рекурсия и Хранимая процедура
|
|||
|---|---|---|---|
|
#18+
Господа ! А в пылу спора слабо поднять топик "Древовидные структуры в SQL" ? И узнать что такой способ хранения с использованием ParentID используют только лохи :-)) См например Удачи ! ... |
|||
|
:
Нравится:
Не нравится:
|
|||
| 23.11.2002, 20:45:05 |
|
||
|
Рекурсия и Хранимая процедура
|
|||
|---|---|---|---|
|
#18+
Вот ссылка http://www.farpost.com/vit/w3design/server/db/sql/tree.htm ... |
|||
|
:
Нравится:
Не нравится:
|
|||
| 23.11.2002, 20:45:59 |
|
||
|
Рекурсия и Хранимая процедура
|
|||
|---|---|---|---|
|
#18+
Re: bantik червь должен посетить каждый узел дважды, один раз с левой стороны и один раз с правой стороны, так что заключительный количество должено быть удвоенное число узлов во всем дереве -Давайте увеличим время обхода дерева вдвое! Следующий запрос будет брать уволенного служащего как параметр и удалять поддерево, расположенное под ним/ней. ... но другие операции, которые зависят от плотности номеров, не будут работать в дереве с промежутками. Например, Вы не сможете находить листья, используя предикат (right-left=1), и не сможете найти число узлов в поддереве, используя значения left и right его корня. -Давайте удаление узла будем сопровождать перелопачиванием всего(!) хвоста дерева с удаленной ноды! (Время - не деньги) Тип дерева определяется задачами, а не задача типами. Если мне нужно подсчитать суммарный размер всех листьев, то там это делается как 2 пальца намочить, а как операции удаление - добавление - давайте потратим серверное время (девать нам его некуда)! В обсуждаемом варианте дерева добавление узла осуществляется лобавлением всего одной записи, удаление - удаляй любой узел - дети сами каскадно отвалятся. Если есть нужда цеплять детей к бабушкам развлекись со своим Нортон Коммандером! И нехрен по некомпетентности ссылки кидать и лохов вспоминать! ... |
|||
|
:
Нравится:
Не нравится:
|
|||
| 23.11.2002, 21:51:22 |
|
||
|
|

start [/forum/topic.php?fid=46&msg=32070808&tid=1818499]: |
0ms |
get settings: |
8ms |
get forum list: |
15ms |
check forum access: |
3ms |
check topic access: |
3ms |
track hit: |
45ms |
get topic data: |
8ms |
get forum data: |
2ms |
get page messages: |
45ms |
get tp. blocked users: |
1ms |
| others: | 207ms |
| total: | 337ms |

| 0 / 0 |
