powered by simpleCommunicator - 2.0.61     © 2026 Programmizd 02
Целевая тема:
Создать новую тему:
Автор:
Закрыть
Цитировать
Форумы / Microsoft SQL Server [игнор отключен] [закрыт для гостей] / И сново дерево
12 сообщений из 12, страница 1 из 1
И сново дерево
    #32036134
AlexanderVS
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
Есть довольно стандартная таблица, реализующая хранение иерархической структуры:
ID,ParentID,Summa,Folder. Поле Folder должно хранить 1 -если данный элемент имеет деток, 0 - соответственно устанавливаем для конечных элементов.
Никак не могу придумать триггер, поддерживающий данное правило, при условии что дерево обновляется не построчно, а пакетной операцией.
Может кто подскажет как решить данную проблему?
...
Рейтинг: 0 / 0
И сново дерево
    #32036158
Фотография ziktuw
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
Убери поле Folder и проблема снимется сама собой. Оно избыточно, так как всегда можно узнать в запросе, есть ли детки или нет у конкретной ноды.
При желании можно написать вьюху, в которой это поле будет вычисленным
...
Рейтинг: 0 / 0
И сново дерево
    #32036159
Фотография SergSuper
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
как-то так например можно

update t set Folder = 0
from tbl t, inserted i
where t.ID=i.ID

update p
set Folder = 1
from tbl t, tbl p, inserted i
where t.ID=p.ParentID and p.ID=i.ID

ну и еще есть масса вариантов. Можно сделать без триггеров - просто VIEW, где бы это поле считалось.
...
Рейтинг: 0 / 0
И сново дерево
    #32036166
Фотография alexeyvg
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
Не согласен, что поле Folder избыточно. В запросе узнавать тяжело для сервера, учитывая, что в приложении на одно обновление приходится 100 - 1000 чтений. А запрос будет вида:
Код: plaintext
1.
2.
3.
select t.ID, t.ParentID, t.Summa,
	case when exists(select * from MyTable t1 where t1.ParentID = t.ID) then  1  else  0  end as Folder
from MyTable t


А вот и триггеры:
Код: 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.
create trigger tU_MyTable on MyTable for update
as

if update(ParentID)
begin
	update MyTable
	set Folder =  1 
	from MyTable t
		join inserted i on i.ParentID = t.ID
		join deleted d on d.ID = i.ID and d.ParentID <> i.ParentID

	update MyTable
	set Folder =  0 
	from MyTable t
		join deleted d on d.ParentID = t.ID
	where not exists(select * from MyTable t1 where t1.ParentID = t.ID)
end
go

create trigger tI_MyTable on MyTable for insert
as

update MyTable
set Folder =  1 
from MyTable t
	join inserted i on i.ParentID = t.ID
go

create trigger tD_MyTable on MyTable for delete
as

update MyTable
set Folder =  0 
from MyTable t
	join deleted d on d.ParentID = t.ID
where not exists(select * from MyTable t1 where t1.ParentID = t.ID)
go
...
Рейтинг: 0 / 0
И сново дерево
    #32036200
Dominic
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
Друзья, а не проще ли так: триггер на вставку наращивает поле Folder на 1 (Default Folder`а - 0), а триггер на удаление - уменьшает его? Тогда в нем всегда будет храниться не только факт наличия "деток" (ненулевой Folder), а еще и их количество. Пример:

CREATE TRIGGER table1_insert
ON table1
FOR INSERT
AS
IF @@ROWCOUNT = 0 'блокирование ложн. срабатывания
RETURN
UPDATE table1
SET Folder = Folder + 1
FROM inserted INNER JOIN table1
ON inserted.ID_PARENT = table1.ID
RETURN

CREATE TRIGGER table1_delete
ON table1
FOR DELETE
AS
IF @@ROWCOUNT = 0
RETURN
UPDATE table1
SET Folder = Folder - 1
FROM deleted INNER JOIN table1
ON deleted.ID_PARENT = table1.ID
RETURN

Тут в конфе где-то неделю назад один умный человек дал ссылку на потрясающую статью (впечатляющего по крайней мере меня, не шибко зубрившего основы древовидных структур). Так вот структура типа обсуждающейся в этой теме (ID, ID_PARENT) называется "направленные графы". А вот в этой статье есть описание альтернативной структуры, позволяющей хранить те же иерархические зависимости, однако объекты в этой структуре оказываются связаными математической зависимостью, зная которую влегкую строится простой SELECT для получения на основе рассматриваемого узла любого вверх или вниз по иерархии.
Я уже 3 года с "направленными графами" вобнимку, в моей структуре при добавлении объекта даже рассчитывается уровень вложенности тригером, все кульно, но: не нравится скорость "ползания" по дереву. Вот приду на работу с курсов, на которых я сейчас нахожусь - буду внедрять "альтернативу". Найдите ссылку на эту статью, почитайте, и попробуем вместе. Там есть кое-что, что мне не нравится, и я хочу применить комбинацию этих способов
...
Рейтинг: 0 / 0
И сново дерево
    #32036251
Фотография SergSuper
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
2 Dominic
Ваш триггер не будет работать если например вставляется папа с двумя детьми, а удаляться будут по одному :)
а статью Вы наверное эту имели ввиду
деревья
...
Рейтинг: 0 / 0
И сново дерево
    #32036390
Gena G.
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
Эх... Нет в SQL рекурсивных запросов... Переходите на DB2 :)
...
Рейтинг: 0 / 0
И сново дерево
    #32036405
Фотография SergSuper
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
а DB2 наверняка чего-нибудь другого нет :)
...
Рейтинг: 0 / 0
И сново дерево
    #32036410
Фотография Jimmy
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
Вот еще статья по теме : Иерархические структуры, не требующие сопровождения
Полюбопытсвуйте, коллеги.
...
Рейтинг: 0 / 0
И сново дерево
    #32036423
Dominic
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
2 SergSuper
Согласен. Вставлять "пачку" записей нельзя. Поэтому у себя в тригере вставил такую блокировку:
...
AS
DECLARE @rowcount INT
SET @rowcount = @@ROWCOUNT
IF @rowcount = 0 'блокирование ложн. срабатывания
RETURN
IF @rowcount > 1
BEGIN
RAISERROR('Нельзя добавлять более 1 записи',16,1)
RETURN
END
...

Самому-то мне все это не сильно нравится. Напомню, что решение организовать хранение объектов в иерархической структуре я принял в условиях лично моей низкой квалификации несколько лет назад, а когда "подрос" - приложение уже было запущено в эксплуатацию и было связано с другими приложениями по классификационным кодам (поле ID таблицы table1 имеет тип INT IDENTITY(1,1))
Приходилось выкручиваться "на ходу" и для основных сущностей предметной области создать и поддерживать реляционные (неиерархические структуры) тригерами table1. Размеры тригеров стали удручать: не меньше 500 строк для каждого события изменения данных. Кроме этого никак не удавалось найти приемлемого решения для события изменения атрибутов таких сущностей. Поэтому и нахожусь в поиске других решений.

По поводу статьи - нет, не эта, хотя эта тоже крайне интересна, еще не прочитал. Я сейчас не на работе, где и закладка на статью и любовно распечатанная и пошитая копия.

По поводу вставки пачки записей (целая ветка). Мне кажется, это можно решить только курсором, причем на содержимое поля ID должно быть наложено ограничение - по крайней мере ID "дочек" должны быть меньше ID своих "пап"
...
Рейтинг: 0 / 0
И сново дерево
    #32036424
Фотография alexeyvg
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
2Gena G.
Можно написать рекурсивную процедуру или триггер. Об этом часто задают вопросы начинающие. Когда у них получается, они радуются. Это очень плохой стиль программирования на SQL - языке структурированных запросов ; что-бы научится правильно программировать на нём, нужно годик заниматься только SQL-ем, близко не подходя к процедурным и объектным языкам, и тогда вырабатывается иммунитет от "рекурсий".
Как - бы не был хорош DB2 со своими рекурсивными запросами, всё равно они, так-же как и запрос типа
select t.ID, t.ParentID, t.Summa,
case when exists(select * from MyTable t1 where t1.ParentID = t.ID) then 1 else 0 end as Folder
from MyTable t
очень неэффективны.
Здесь предлагается нормальный выход - умеренная денормализация данных с поддержкой на триггере - вопрос только, как считать.
Извините за эмоции - наболело... Я помню, в этом форуме один из таких начинающих возмущался - MS SQL Server недостаточно красиво, хуже чем Аксесс, рисует комбобоксы :-(
...
Рейтинг: 0 / 0
И сново дерево
    #32036475
Фотография SergSuper
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
2 Dominic
По поводу вставки пачки записей (целая ветка). Мне кажется, это можно решить только курсором, причем на содержимое поля ID должно быть наложено ограничение - по крайней мере ID "дочек" должны быть меньше ID своих "пап"
Нет, курсор здесь не нужен. Можно через временную таблицу - считать сколько дочек добавляется, а потом уже обновлять в основной.
Как-то так(не проверял, только мысль пишу)
Код: plaintext
1.
2.
3.
4.
5.
6.
7.
8.
9.
10.
11.
 ...
declare @t table(id int, fcount int)
insert @t
select t.ID, count(*)
from table1 t, inserted i
where i.ID_PARENT = t.ID 

UPDATE t 
SET Folder = Folder + fcount 
FROM table1 t, @t m
where m.id=t.ID
...
Рейтинг: 0 / 0
12 сообщений из 12, страница 1 из 1
Форумы / Microsoft SQL Server [игнор отключен] [закрыт для гостей] / И сново дерево
Найденые пользователи ...
Разблокировать пользователей ...
Читали форум (0):
Пользователи онлайн (0):
x
x
Закрыть


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