powered by simpleCommunicator - 2.0.61     © 2026 Programmizd 02
Целевая тема:
Создать новую тему:
Автор:
Закрыть
Цитировать
Форумы / Microsoft SQL Server [игнор отключен] [закрыт для гостей] / Рекурсия и Хранимая процедура
25 сообщений из 32, страница 1 из 2
Рекурсия и Хранимая процедура
    #32070304
Chainiko
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Гость
Существует таблица FILES вида
Код: plaintext
1.
2.
3.
4.
5.
6.
7.
8.
9.
10.
11.
12.
13.
  NodeId     NodeName NodeType ParentId PreviousId     Size
        1            C:    Drive              
        2           DOS   Folder         1 
        3    config.sys     File         2                    62 
        4     himem.sys     File         2            3        128 
        5           DOC   Folder         1 
        6        SUBDOC   Folder         5 
        7        s1.doc     File         6                 45578 
        8        s2.doc     File         6            7        654 
        9          1 .txt     File         5            6       1244 
       10          2 .txt     File         5            9        458 
       11     MSDOS.SYS     File         1            5         54 
       12   COMMAND.COM     File         1           11      15486 

описывающая дерево каталогов на диске С:

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.
CREATE PROCEDURE GetSize @n_id int, @allsize int output as

DECLARE cicle_cursor CURSOR FOR
  SELECT F1.node_id As nchild_id
  FROM FILES AS F LEFT JOIN FILES AS F1 ON F.node_id = F1.parent_id
  WHERE F.node_id=@n_id AND F1.node_type= "Folder" 

  OPEN cicle_cursor

  FETCH NEXT FROM cicle_cursor
  INTO @nchild_id

  WHILE @@FETCH_STATUS =  0   /* Цикл по всем нодам типа Folder в текущей ноде. */ 
   BEGIN
	SELECT @allsize = @allsize + (SELECT Sum(F1.size)
	FROM FILES AS F LEFT JOIN FILES AS F1 ON F.node_id = F1.parent_id
	WHERE F.node_id=@nchild_id)
	 /* Вот здесь неплохо бы рекурсивно вызвать самого себя ????? */ 
	SEELCT @allsize = @allsize + exec GetSize @nchild_id  /* только будет ли так работать */ 

	FETCH NEXT FROM cicle_cursor
	INTO @nchild_id
   END
GO


Бред, конечно, но какие еще есть варианты? Pls!
...
Рейтинг: 0 / 0
Рекурсия и Хранимая процедура
    #32070425
Vetal
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
Так у тебя точно ничего не получится, так как, насколько я понимаю, курсор вещь глобальная, и если ты его открываешь, а потом входишь в рекурсию, то ты внутри рекурсии открыть курсор не сможешь, так как он уже был однажды открыт (проверено). Более того, когда ты сделаешь 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 максимум (тебе должно хватить с головой). При завершении триггеров все удаленные каталоги восстановлятся. Данные не пропадут, так как все выполняется в контексте одной транзакции
...
Рейтинг: 0 / 0
Рекурсия и Хранимая процедура
    #32070430
Фотография VVG_
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
Если SQL2000, то можно создать пару рекурсивных функций, с помощью которых это решается. Если интересует, то завтра подробно расскажу.
...
Рейтинг: 0 / 0
Рекурсия и Хранимая процедура
    #32070441
Chainiko
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Гость
Re VVG_. Спасибо, подожду до завтра.
...
Рейтинг: 0 / 0
Рекурсия и Хранимая процедура
    #32070445
Chainiko
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Гость
Re Vetal: Идея неплоха, я ее потестирую, но:
- во-первых, глубина рекурсии 32 - очень мала, это в данном примере, для понимания сути приведены файлы в каталогах, но в реальной базе глубина дерева достигает нескольких сотен, единиц тысяч...
- во-вторых, не очень понятно с удалением, если транзакция не завершается, то физического удаления не происходит, и, можно считать, что на времени выполнения это не сказывается?

Если на рекурсии накладываются такие ограчничения, можно ли в такой таблице обойтись без рекурсии?
...
Рейтинг: 0 / 0
Рекурсия и Хранимая процедура
    #32070456
Фотография Gobzo Kobler
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
PreviousId - бред сивой кобылы, ошибка дизайна. Ну да ладно, это маловажная вещь. Но зачем вам понадобилось строить дерево неопределенной глубины на реляционной базе и делать обработку на сервере - вот этого уже я никак понять не могу.
Сама концепция реляционной базы предотвращяет ее использование для древовидных данных. Обрабатывайте деревья на клиенте и будет вам радость. Сервер закопается стопудово, особенно если вы увлечетесь курсорами.
...
Рейтинг: 0 / 0
Рекурсия и Хранимая процедура
    #32070470
Chainiko
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Гость
Re: Gobzo Kobler
Дело в том, что дерево с кучей узлов и неопределенной глубины - это всего одна таблица - основа базы. К каждой ноде привязано куча таблиц и данных в них именно реляционных. Там уже тысячи запросов, сотни мегабайт данных, поэтому переделывать эту таблицу не хочу. С такой структурой таблицы (ParentID, PreviousID) методами FirstChild и Next в рекурсии на контроле строится дерево и поддержаны куча методов по движению нод, и т.д. и т.п, а зная NodeId, основная работа ведется с недревовидной частью базы.

Но это уже тема отдельного разговора. Вернемся к баранам, может можно обойтись без рекурсии?
...
Рейтинг: 0 / 0
Рекурсия и Хранимая процедура
    #32070484
Vetal
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
Re Chainiko
Вообще-то ограничение на глубину рекурсии насколько я знаю, накладывается только на триггеры. Если все написать как-то через хранимые процедуры, то там таких ограничений вроде как нет.

Что касается того, что данные не удаляются, то ведь они же и не должны удаляться, информация должна только подсчитываться. А на производительность это конечно же влияет, так как время на выполнение кода в триггере все-равно тратится.

Если же ты все это хочешь сделать на стороне сервера, то напиши расширенную хранимую процедуру (extended sp), в ней ты можешь воспользоваться функиями языка C, и эта процедура будет выполняться на сервере.
...
Рейтинг: 0 / 0
Рекурсия и Хранимая процедура
    #32070534
Фотография Chicago
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
Если циклов нет, то будет работать

Код: 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.
create procedure GetSize 
        @node_id int, 
        @size int output 
as
begin tran

declare @err int, @rc int

 -- таблица для очереди узлов
 
create table #queue(node_id int) on [primary]

set @err=@@error
if @err<> 0  goto l_err

alter table #queue add constraint
	PK_queue primary key clustered 
	(
	node_id
	) ON [PRIMARY]

set @err=@@error
if @err<> 0  goto l_err

insert into #queue(node_id) values(@node_id)
set @err=@@error
if @err<> 0  goto l_err

declare @current_id int, @node_size int

set @size= 0 

while  1 = 1 
begin
        select top  1  @current_id=node_id from #queue        
        select @err=@@error, @rc=@@rowcount
        if @err<> 0  or @rc= 0  break

        set @node_size= 0 

        select @node_size=isnull([size],  0 ) from files where nodeid=@current_id
        select @err=@@error
        if @err<> 0  break

        set @size = @size + @node_size
        
        delete from #queue where node_id=@current_id

        insert into #queue(node_id) select nodeid from files where parentid=@current_id
        select @err=@@error
        if @err<> 0  break
end

if @err<> 0  goto l_err
drop table #queue

commit tran
return @@error

l_err:
        if @@trancount> 0  rollback tran
        set @size=null
        return @err
...
Рейтинг: 0 / 0
Рекурсия и Хранимая процедура
    #32070623
Фотография 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.
38.
39.
40.
41.
42.
43.
44.
45.
create table Files 
(NodeID int not null, NodeName varchar( 1024 ) not null, 
NodeType varchar( 20 ) not null, ParentId int null, 
PreviousID int null, Size int null)
go
insert into files
select  1 ,'c:','Drive',null,null,null union 
select  2 ,'DOS','Folder', 1 ,null,null union
select  3 ,'config.sys','File', 2 ,null, 62  union
select  4 ,'himem.sys','File', 2 , 3 , 128  union
select  5 ,'DOC','Folder', 1 ,null,null union
select  6 ,'SUBDOC','Folder', 5 ,null,null union
select  7 ,'s1.doc','File', 6 ,null, 45578  union
select  8 ,'s2.doc','File', 6 , 7 , 654  union
select  9 ,'1.txt','File', 5 , 6 , 1244  union
select  10 ,'2.txt','File', 5 , 9 , 458  union
select  11 ,'MSDOS.SYS','File', 1 , 5 , 54  union
select  12 ,'COMMAND.COM','File', 1 , 11 , 15486 
go
create function dbo.udf_Nodes(@ParentID int)
returns @Tbl table (NodeID int,NodeSize int)
as
begin
 insert into @Tbl
 select NodeID,dbo.udf_NodeSize(NodeID) from files where ParentID=@ParentID
 return
end
go
create function dbo.udf_NodeSize (@NodeID int)
returns int
as
begin
 declare @Size int
 select @Size=case NodeType
  when 'Drive' then (select sum(NodeSize) from dbo.udf_Nodes(@NodeID))
  when 'Folder' then (select sum(NodeSize) from dbo.udf_Nodes(@NodeID))
  when 'File' then Size
 end from files where NodeID=@NodeID
 return @Size
end
go
select *,dbo.udf_NodeSize(NodeID) as NodeSize from files
go
drop table files
drop function udf_Nodes
drop function udf_NodeSize
...
Рейтинг: 0 / 0
Рекурсия и Хранимая процедура
    #32070643
Фотография Chicago
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
Мой предыдущий вариант лобовой и, следовательно, не слишком оптимальный. А вот более прогрессивное решение.

Код: 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.
create procedure GetSize 
        @node_id int, 
        @size int output 
as
begin tran

declare @err int, @rc int

create table #subtree(node_id int not null, [size] int, layer int) on [primary]

set @err=@@error
if @err<> 0  goto l_err

alter table #subtree add constraint
	PK_queue primary key clustered 
	(
	node_id
	) ON [PRIMARY]

set @err=@@error
if @err<> 0  goto l_err

declare @layer int
set @layer =  0 

insert into #subtree(node_id, [size], layer) 
        select nodeid, [size], @layer from files where nodeid=@node_id

set @err=@@error
if @err<> 0  goto l_err

while  1 = 1 
begin
        set @layer=@layer+ 1 

        insert into #subtree(node_id, [size], layer) 
                select nodeid, [size], @layer from files 
                        where parentid in (select node_id from #subtree where layer=@layer- 1 )
                        
        select @err=@@error, @rc=@@rowcount
        if @err<> 0  or @rc= 0  break
end

select @size=sum([size]) from #subtree
set @size=isnull(@size,  0 )

if @err<> 0  goto l_err
drop table #subtree

commit tran
return @@error

l_err:
        if @@trancount> 0  rollback tran
        set @size=null
        return @err


ЗЫ. Итерация свойственна человеку, рекурсия - божественна
...
Рейтинг: 0 / 0
Рекурсия и Хранимая процедура
    #32070658
nandji
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
интересное решение Древовидные структуры в SQL
...
Рейтинг: 0 / 0
Рекурсия и Хранимая процедура
    #32070808
Vetal
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
Мой модифицированный вариант. Вместо триггеров теперь рекурсивно вызываются процедуры, и, соответственно, нет ограничения 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 использовать как возвращаемый параметр функции, а не как глобальную переменную
...
Рейтинг: 0 / 0
Рекурсия и Хранимая процедура
    #32070831
Фотография Chicago
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
2Vetal:

Вместо триггеров теперь рекурсивно вызываются процедуры, и, соответственно, нет ограничения 32.

Смотрим BOL, раздел SQL Server Architecture / Implementation Details / Maximum Capacity Specifications. Видим
Nested stored procedure levels = 32

Nested trigger levels = 32

No comments
...
Рейтинг: 0 / 0
Рекурсия и Хранимая процедура
    #32070852
Фотография Chicago
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
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.
insert into files
select  1 ,'c:','Drive',null,null,null union 
select  2 ,'DOS','Folder', 1 ,null,null union
select  3 ,'config.sys','File', 2 ,null, 62  union
select  3 ,'config.sys','File', 2 ,null, 62  union
select  4 ,'config.sys','File', 3 ,null, 62  union
select  5 ,'config.sys','File', 4 ,null, 62  union
select  6 ,'config.sys','File', 5 ,null, 62  union
select  7 ,'config.sys','File', 6 ,null, 62  union
select  8 ,'config.sys','File', 7 ,null, 62  union
select  9 ,'config.sys','File', 8 ,null, 62  union
select  10 ,'config.sys','File', 9 ,null, 62  union
select  11 ,'config.sys','File', 10 ,null, 62  union
select  12 ,'config.sys','File', 11 ,null, 62  union
select  13 ,'config.sys','File', 12 ,null, 62  union
select  14 ,'config.sys','File', 13 ,null, 62  union
select  15 ,'config.sys','File', 14 ,null, 62  union
select  16 ,'config.sys','File', 15 ,null, 62  union
select  17 ,'config.sys','File', 16 ,null, 62  union
select  18 ,'config.sys','File', 17 ,null, 62  union
select  19 ,'config.sys','File', 18 ,null, 62  union
select  20 ,'config.sys','File', 19 ,null, 62  union
select  21 ,'config.sys','File', 20 ,null, 62  union
select  22 ,'config.sys','File', 21 ,null, 62  union
select  23 ,'config.sys','File', 22 ,null, 62  union
select  24 ,'config.sys','File', 23 ,null, 62  union
select  25 ,'config.sys','File', 24 ,null, 62  union
select  26 ,'config.sys','File', 25 ,null, 62  union
select  27 ,'config.sys','File', 26 ,null, 62  union
select  28 ,'config.sys','File', 27 ,null, 62  union
select  29 ,'config.sys','File', 28 ,null, 62  union
select  30 ,'config.sys','File', 29 ,null, 62  union
select  31 ,'config.sys','File', 30 ,null, 62  union
select  32 ,'config.sys','File', 31 ,null, 62  union
select  33 ,'config.sys','File', 32 ,null, 62  union
select  34 ,'config.sys','File', 33 ,null, 62  union
select  35 ,'config.sys','File', 34 ,null, 62  

и на прогоне получаем

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 ограничение вложенности распространяется.
...
Рейтинг: 0 / 0
Рекурсия и Хранимая процедура
    #32070860
Фотография VVG_
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
Млин, отвоевал ты свой вариант, отвоевал.
Но иметь 32 уровня вложенности папок на диске - это перебор.
...
Рейтинг: 0 / 0
Рекурсия и Хранимая процедура
    #32071101
Chainiko
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Гость
Да, господа, много я проспал. Пока выяснялось, что на ХП тоже есть ограничение на рекурсию я слепил кусок кода, работающего на 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.
Public allSize As Long
Public cnn As ADODB.Connection

Private Sub Form_Load()
  Set cnn = New ADODB.Connection
  cnn.Provider =  "Microsoft.Jet.OLEDB.4 . 0 "
  cnn.Mode = adModeShareExclusive
  cnn.Open  "E:\Progects\databasefile\db1.mdb" 
  Tree  5    /*DOC : NodeID = 5 */ 
  Debug.Print allSize
End Sub

Private Sub Tree(ParentNodeID As Long)
  Dim nodeID As Long
  Dim RS As ADODB.Recordset
  Dim strSQL As String
    strSQL =  "SELECT * "  & _
       "FROM FILES AS F LEFT JOIN FILES AS F1 ON F.node_id = F1.parent_id "  & _
       "WHERE F.node_id = "  & ParentNodeID &  " AND F1.previous_id Is Null" 
  Set RS = cnn.Execute(strSQL)
  nodeID =  0 
  On Error Resume Next
  nodeID = RS( "F1.node_id" )  /* получаем первого Childа */ 
  If nodeID =  0  Then RS.Close: Exit Sub ' /* если Childа нет выходим */ 
  allSize = allSize + RS( "F1.size" )  /* если Child есть берем его размер */ 
  RS.Close
  
  Do While True
    Tree (nodeID)  /*вызываем сами себя*/ 
    strSQL =  "SELECT * "  & _
         "FROM FILES "  & _
         "WHERE FILES.previous_id = "  & nodeID
    Set RS = cnn.Execute(strSQL, adOpenKeyset)
    nodeID =  0 
    On Error Resume Next
    nodeID = RS( "node_id" )  /*получаем Nextа */ 
    If nodeID =  0  Then RS.Close: Exit Sub  /*сли Nextа нет выходим */ 
    allSize = allSize + RS( "size" )  /*если Next есть берем его размер */ 
    RS.Close
  Loop
End Sub


ЗЫ. На используемого провайдера просьба бочку не катить, это так, для тестов.
...
Рейтинг: 0 / 0
Рекурсия и Хранимая процедура
    #32071118
Фотография Chicago
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
2 Chainiko:

Не-е-е, сам транслируй свой VB в T-SQL. Скажу честно, на твоей задаче мы вчера классно оттянулись, написали то, что считали нужным написать в данном случае и писать по другому нам банально не интересно.

Плохо знаешь синтаксис T-SQL? Ну вот и замечательно! Отличный повод потренироваться!!! В ветке полно интересных примеров. Их можно использовать как источник вдохновения.

return procedure -> return [<return value>]

Я тоже не знаю чему будет равен @nodeid, если запрос не вернет записей. В документации этот вопрос слабо освещен. Поэтому я бы вообще не делал на этот счет никаких предположений. Сегодня так, а в MS SQL Server XP 2010 может быть по другому. Зато точно известно, что если запрос не вернет записей, то сразу после его завершения переменная @@rowcount будет равна 0. В нашем случае это все, что нужно.

P.S. Не следует обижаться, но VB вам тоже нужно подучить.
...
Рейтинг: 0 / 0
Рекурсия и Хранимая процедура
    #32071125
Flint-San
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Гость
Тут вроде код sp просили, предлагаю свой вариант.
Код: plaintext
1.
2.
3.
4.
5.
6.
7.
8.
9.
10.
11.
12.
13.
14.
15.
16.
17.
18.
CREATE PROCEDURE GetSize @n_id int, @allsize bigint output 
AS
 SET @allsize= 0 

 SELECT DISTINCT NodeId INTO #AllChilds FROM FILES WHERE ParentId=@n_id

 WHILE(@@ROWCOUNT> 0 )
   INSERT INTO #AllChilds(NodeID) 
   SELECT DISTINCT F.NodeId FROM #AllChilds a, FILES F 
   WHERE F.ParentId=a.NodeId
     AND NOT EXISTS(SELECT TOP  1   1  FROM #AllChilds X WHERE X.NodeId=F.NodeId)
 
 SELECT @allsize=sum(ISNULL(F.Size, 0 )) FROM #AllChilds a,FILES F WHERE F.NodeId=a.NodeId
GO

DECLARE @allsize bigint
EXEC GetSize  5 , @allsize OUT
SELECT @allsize
...
Рейтинг: 0 / 0
Рекурсия и Хранимая процедура
    #32071575
Chainiko
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Гость
Re Chicago:

P.S. Не следует обижаться, но VB вам тоже нужно подучить.
Если Вас не затруднит, не укажете ли на ошибки, это конечно не VB форум, но если уж А, то и Б нужно говорить. Мне это только на пользу пойдет.
...
Рейтинг: 0 / 0
Рекурсия и Хранимая процедура
    #32071576
Chainiko
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Гость
Re: Flint-San
Очень понравилась Ваша процедура. Коротко и со вкусом. Только нихрена не понятно как работает! Не могди бы объяснить Чайнику, коротко, в двух-трех словах? Заранее благодарю.
...
Рейтинг: 0 / 0
Рекурсия и Хранимая процедура
    #32071651
bantik
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
Господа !

А в пылу спора слабо поднять топик "Древовидные структуры в SQL" ? И узнать что такой способ хранения с использованием ParentID используют только лохи :-))

См например

Удачи !
...
Рейтинг: 0 / 0
Рекурсия и Хранимая процедура
    #32071652
bantik
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
Вот ссылка

http://www.farpost.com/vit/w3design/server/db/sql/tree.htm
...
Рейтинг: 0 / 0
Рекурсия и Хранимая процедура
    #32071667
Chainiko
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Гость
Re: bantik

червь должен посетить каждый узел дважды, один раз с левой стороны и один раз с правой стороны, так что заключительный количество должено быть удвоенное число узлов во всем дереве

-Давайте увеличим время обхода дерева вдвое!

Следующий запрос будет брать уволенного служащего как параметр и удалять поддерево, расположенное под ним/ней. ... но другие операции, которые зависят от плотности номеров, не будут работать в дереве с промежутками. Например, Вы не сможете находить листья, используя предикат (right-left=1), и не сможете найти число узлов в поддереве, используя значения left и right его корня.

-Давайте удаление узла будем сопровождать перелопачиванием всего(!) хвоста дерева с удаленной ноды! (Время - не деньги)

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

В обсуждаемом варианте дерева добавление узла осуществляется лобавлением всего одной записи, удаление - удаляй любой узел - дети сами каскадно отвалятся. Если есть нужда цеплять детей к бабушкам развлекись со своим Нортон Коммандером! И нехрен по некомпетентности ссылки кидать и лохов вспоминать!
...
Рейтинг: 0 / 0
Рекурсия и Хранимая процедура
    #32071727
Фотография MiCe
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
поиск посату работает.....
...
Рейтинг: 0 / 0
25 сообщений из 32, страница 1 из 2
Форумы / Microsoft SQL Server [игнор отключен] [закрыт для гостей] / Рекурсия и Хранимая процедура
Найденые пользователи ...
Разблокировать пользователей ...
Читали форум (0):
Пользователи онлайн (0):
x
x
Закрыть


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