powered by simpleCommunicator - 2.0.61     © 2026 Programmizd 02
Целевая тема:
Создать новую тему:
Автор:
Закрыть
Цитировать
Форумы / Microsoft SQL Server [игнор отключен] [закрыт для гостей] / Рекурсия и Хранимая процедура
7 сообщений из 32, страница 2 из 2
Рекурсия и Хранимая процедура
    #32071750
Фотография Chicago
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
Если Вас не затруднит, не укажете ли на ошибки, это конечно не VB форум, но если уж А, то и Б нужно говорить. Мне это только на пользу пойдет.

Ошибки стиля рассматривать не будем, стиль у каждого разный и не все есть ошибка. (Хотя очень хочется :-) Также разбор полетов ограничим процедурой Tree, поскольку все остальное писано специально для тестирования и некоторые шероховатости не имеют большого значения.

Начнем с того что Rs("F1.node_id") писать нельзя. Нужно Rs("node_id"). А если в запросе 2 node_id из разных таблиц, то извольте указать им различные псевдонимы и используйте последние как имена полей в VB. В противном случае всегда будете получать значение того node_id, что в коллекции Rs.Fields является первым. Далее будем полагать, что этой ошибки нет.

Ваша основная ошибка заключается в стратегии обработки ошибок. У вас есть 2 строки вида
on error resume next . При этом вторая, та что внутри while (стиль ужасен, извините, не удержался 8-) по большому счету не нужна. Начиная с первой такой строки и вплоть до выхода из процедуры, управление при ошибках будет передаваться на следующий оператор. В связи с этим возможны следующие сценарии.

Первый селект вернул строку, не имеющую размера (size is null). Тогда строка allSize = allSize + RS("F1.size") вызывает ошибку (нельзя складывать Null и целое число). Но об этой ошибке вы не узнаете. И конечное значение будет не вполне корректно. (Хотя, возможно, null=0, есть правильно)


Сценарий второй. Очередной cnn.Execute внутри цикла while. Завершился неудачей (Timeout expired, connection broken или еще какая-нибудь хрень). Вы об этом не узнаете (действует первый on error resume next). Выполнение продолжится. В строке nodeID = RS("node_id") происходит ошибка, ведь рекордсет не открыт, и nodeID остается равным 0. В последующем If мы закрываем закрытый рекордсет. Ошибка! А нам все пофиг, resume next, вашу мать. Дальше следует exit sub. Все это тихо и молча. В результате какая-то часть узлов не оказывает влияния на результат, а вы об этом ничего не знаете. Для вас процедура завершилась успешно.

Ну и под занавес все таки об ошибке стиля. Какого хрена allSize глобальная переменная? Это же результат вычислений! Он должен возвращаться! Только так и без объяснений. (Извините, но если начну объяснять, то сразу вспомню, как мне пришлось отлаживать программулину, писанную одним товарищем, чтоб ему... там было 3247 глобальных переменных... говорить об этом могу только матом).
...
Рейтинг: 0 / 0
Рекурсия и Хранимая процедура
    #32071757
Фотография Chicago
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
По поводу процедуры Flint-San:

Основная идея на первом шаге он помещает во временную таблицу id корневого узла. Далее в цикле он добавляет вершины, отцы которых уже находятся в таблице. При этом если вершина уже добавлена, то она не добавляется. Цикл продолжается, пока на очередном шаге не будет добавлено ни одной вершины. В таблице оказываются все узлы поддерева, суммарный вес вершин, которого и нужно подсчитать. Что и делается в последнем select.

Кстати его процедура не учитывает вес корневого узла. Если это необходимо замениете
Код: plaintext
SELECT DISTINCT NodeId INTO #AllChilds FROM FILES WHERE ParentId=@n_id
на
Код: plaintext
SELECT DISTINCT NodeId INTO #AllChilds FROM FILES WHERE NodeId=@n_id


Фактически это то же, что и в моем варианте №2. Короче, потому что начисто проигнорированна обработка ошибок. Ну и о временной таблице вам придется самому заботиться. Insert Into ее создаст конечно, а вот удаления или очистки там нет. В результате если вы в рамках одного коннекта вызовите процедуру дважды, для произвольной вершины и затем для ее потомка, то при первом вызове получите корректный результат, а при втором нет. Вернется вес первого поддерева, а не второго. Вот она прелесть глобальных данных! (это я к своему предыдущему постингу)
...
Рейтинг: 0 / 0
Рекурсия и Хранимая процедура
    #32071830
Фотография Chicago
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
Следующий текст из предыдущего постинга:

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

просьба считать несуществующим :-) Sorry, прогнал...
...
Рейтинг: 0 / 0
Рекурсия и Хранимая процедура
    #32071890
Flint-San
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Гость
Не думал, что это тема еще обсуждается.
Chicago:
Код правильный и ненужно его корректировать так как
из задачи корневой узел это дирректорий, по вставляемым
записям у дирректория Size IS NULL и размер определ-ся только по файлом.
Теперь к вам вопрос, что даст ваше исправление?
Код: plaintext
1.
 SELECT DISTINCT NodeId INTO #AllChilds FROM FILES WHERE NodeId=@n_id
вместо
Код: plaintext
1.
 SELECT DISTINCT NodeId INTO #AllChilds FROM FILES WHERE ParentId=@n_id

Правильно абсолютно ничего как для файла так и для каталога. Смысл вашего первого запроса, бесмысленен.
У этой процедуры есть только один существенный недостаток, а именно ее скорость будет зависить от числа вложенных каталогов.
Что же касается удаления временной таблицы... Процедура автоматически удаляет временную таблицу по выходу из нее.
Chainiko:
просто нашел всех детей(NodeId) по родителям(ParentID)
при добавлении в таблицу проверяю есть ли там уже такой child или нет.
...
Рейтинг: 0 / 0
Рекурсия и Хранимая процедура
    #32072305
Flint-San
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Гость
К Chicago:
>>Правильно абсолютно ничего как для файла так и для >>каталога. Смысл вашего первого запроса, бесмысленен.
Признаю свою ошибку , так как смыл вашего исправления
позволит расчитать размер одного файла.
Chainiko замени плиз код с
Код: plaintext
 SELECT DISTINCT NodeId INTO #AllChilds FROM FILES WHERE ParentId=@n_id 

на
Код: plaintext
SELECT DISTINCT NodeId INTO #AllChilds FROM FILES WHERE NodeId=@n_id

чтобы процедура могла расчитывать абсолютно все, включая и размер одного файла.
...
Рейтинг: 0 / 0
Рекурсия и Хранимая процедура
    #32072314
Фотография Chicago
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
Я думаю пришли к консенсусу.

2Flint-San:

Спасибо. Я от вас узнал для себя нечто новое:

Что же касается удаления временной таблицы... Процедура автоматически удаляет временную таблицу по выходу из нее.

If you create a local temporary table inside a stored procedure, the temporary table exists only for the purposes of the stored procedure; it disappears when you exit the stored procedure.


Что-то редко такое стало происходить... Деградировать что-ли начинаю? ;-(
...
Рейтинг: 0 / 0
Рекурсия и Хранимая процедура
    #32072520
Chainiko
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Гость
Re Chicago
Огромное спасибо. Очень признателен за указанные ошибки! Приятно, что Вы все очень подробно описали. Со всем согласен.
On Error Resume Next - 2 раза действительно погорячился, а влепил его потому, что много надо было писать кода на проверки возвращаемых значений: есть ли записи в рекордсете, если есть, то поле NULL или нет, и только когда есть значение - инкрементировать.
Еще раз благодарю.
...
Рейтинг: 0 / 0
7 сообщений из 32, страница 2 из 2
Форумы / Microsoft SQL Server [игнор отключен] [закрыт для гостей] / Рекурсия и Хранимая процедура
Найденые пользователи ...
Разблокировать пользователей ...
Читали форум (0):
Пользователи онлайн (0):
x
x
Закрыть


Просмотр
0 / 0
Close
Debug Console [Select Text]