Гость
Целевая тема:
Создать новую тему:
Автор:
Форумы / Microsoft SQL Server [игнор отключен] [закрыт для гостей] / Иерархии с сортировкой внутри уровня. / 12 сообщений из 12, страница 1 из 1
20.12.2001, 14:28
    #32019457
piton
Гость
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Иерархии с сортировкой внутри уровня.
Есть некоторый иерархический рубрикатор. Сделан стандартно, в одной таблице, следующей структуры


ID NAME PARENT_ID LEVEL ORDER PATH
1 'Рубрика 1' NULL 1 1 '0001'
2 'Рубрика 1.1' 1 2 1 '0001 0001'
3 'Рубрика 1.1.1' 2 3 1 '0001 0001 0001'
4 'Рубрика 1.1.2' 2 3 2 '0001 0001 0002'
5 'Рубрика 1.2' 1 2 2 '0001 0002'
6 'Рубрика 1.3' 1 2 3 '0001 0003'
...


Поле ORDER - порядок следования элементов с общим родителем в пределах одного уровня.
Поле PATH используется для выборки раскрытого дерева одним запросом (сортировка по нему дает упорядоченное дерево, где дети находятся точно под своими родителями, остается только при выводе сдвинуть их вправо на значение поля LEVEL)
Теперь же добавилась задача двигать элементы c общим родителем относительно друг друга (вверх-вниз)
Чтобы сохранить нормальную функциональность поля PATH, в этом случае после сдвижки нужно производить глобальный апдейт поля PATH для всех детей двух меняющихся местами элементов, что не очень нравится. Есть какие-либо другие решения для организации иерархий с динамическим порядком следования внутри уровня, не требующие подобных телодвижений? Чтобы оставалась возможность выбирать выстроенное дерево одним запросом и не осуществлять множественных апдейтов при изменении положения элементов?
Кстати, та же проблема встает и при редактировании иерархии - перемещении одних разделов в другие.

Прошу помочь, заранее спасибо.
...
Рейтинг: 0 / 0
20.12.2001, 15:02
    #32019463
Иерархии с сортировкой внутри уровня.
Все эти вещи легко решаются, если из перечисленных полей хранить только ID, NAME и PARENT_ID. Остальные поля (LEVEL,ORDER,PATH) должны вычисляться в процедуре вывода (раскрутки) дерева. Если следовать такому принципу, то все изменения структуры дерева делаются с полпинка единичными изменениями поля PARENT_ID.
Конечно, выбрать дерево одним запросом не получиться. Зато получиться выбрать дерево одной хранимой процедурой, что не очень сильно отличается от условия "один запрос".
...
Рейтинг: 0 / 0
21.12.2001, 07:49
    #32019514
Sergey Vinogradov
Участник
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Иерархии с сортировкой внутри уровня.
Посмотри статью про иерархию: http://rdbms.narod.ru/article/tree/index.html

Вариант со связанной таблицей работает очень быстро, одним запросом, и таблицу не надо всю перестраивать.
...
Рейтинг: 0 / 0
21.12.2001, 09:55
    #32019532
piton
Гость
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Иерархии с сортировкой внутри уровня.
To Sergey Vinogradov
Я конечно извиняюсь, но при твоем варианте с применением карты дерева в отдельной таблице у меня не получается составить запрос выводящий отсортированное раскрытое дерево.
Я был бы тебе очень благодарен, если бы ты привел пример запроса
...
Рейтинг: 0 / 0
21.12.2001, 10:41
    #32019549
Иерархии с сортировкой внутри уровня.
читал когда-то статью в DBMS Magazine в (ох!) 1996 году
там как раз знаменитый (хотя у некоторых и вызывающий аллергию Joe Celko
расписывал метод представления деревьев с его точки зрения наиболее естественный для SQL
http://www.dbmsmag.com/9603d06.html
единственный сомнительный момент - поддержка этой структуры требует довольно сложных триггеров.
ну и что? простые вещи клепать скушно
...
Рейтинг: 0 / 0
21.12.2001, 11:04
    #32019555
qu-qu
Участник
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Иерархии с сортировкой внутри уровня.
Угу, идея хранения деревьев по принципу "вложенных множеств" - красивая...
(вот тоже самое по-русски)
http://sdm.viptop.ru/articles/sqltrees.html

Но она позволяет только легко и просто - развертывать "иерархии" до "10-го колена", или вытаскивать "пути" наверх до "рута" включительно, а вот не менее простую задачу - показать список "детей" одного узла (без "внуков" и "правнуков") - я что-то не смог придумать - как реализовать в такой структуре, так что - старая добрая ссылка на PARENT_ID - тоже себя оправдывает...
)
...
Рейтинг: 0 / 0
21.12.2001, 11:09
    #32019556
Иерархии с сортировкой внутри уровня.
оп-па. извиняюсь. оказывается на narod.ru лежит как раз оно в переведенном и упрощенном виде и со ссылкой.

а отсортированное по заданному полю дерево ИМХО можно сделать только если все тот же PATH
делать функцией которая пробегает курсором по
SELECT <ваше_поле_сортировки> FROM <ваша_Таблица> Parents Where Child.NodeLeft between Parents.NodeLeft and Parents.NodeRight Order by Parents.NodeLeft
чтобы сорт-код был нормальным надо его по вкусу разбавить разделителями и добить с нужной стороны пробелами.
Под MS2k это работает нормально.
тем у кого функций нет, видимо только процедуры.
Счастливые пользователи Sybase SQL Anywhere могут воспользоваться встроенной функцией LIST(...)
...
Рейтинг: 0 / 0
21.12.2001, 11:24
    #32019562
Иерархии с сортировкой внутри уровня.
2 qu-qu:
Элементарно!
Всего-то и нужно сосчитать родителей.
Берем NodeLeft и NodeRight родителя и выбираем те записи для которых различие в уровне с родителем ровно 1
---
SELECT C.PK, C.name FROM <Table> C, <Table> P
Where
(C.nodeleft between @parentNodeLeft and @ParentNodeRight )
and (P.nodeleft between @parentNodeLeft and @ParentNodeRight)
and (C.nodeleft between P.nodeleft and P.noderight )
Group BY C.PK, C.name
Having Count(P.PK)=2
...
Рейтинг: 0 / 0
21.12.2001, 12:14
    #32019568
piton
Гость
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Иерархии с сортировкой внутри уровня.
Мне не очень понятен способ с nodeleft и noderight
Я правильно понял, при каждой операции (добавлении очередного узла в любое место) их опять надо пересчитывать? Так это - тот же глобальный апдейт, от которого и хотелось убежать.
Я все-таки хотел узнать, нет ли варианта построения иерархии вообще без всяких глобальных апдейтов и рекурсивных движений по дереву. Добавление элемента одиночным инсертом (или двумя в разные таблицы), выборка одним запросом (пусть и сложным)
Получается нет способа?
...
Рейтинг: 0 / 0
24.12.2001, 07:04
    #32019645
Sergey Vinogradov
Участник
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Иерархии с сортировкой внутри уровня.
Чтобы сортировать одним запросом,
надо использовать рекурсию, либо фунцию написать.

Но можно извратиться и без этого.
Основная таблица - [T]( [ID], [NAME], [PARENT_ID], [LEVEL], [ORDER] ).
Вспомогательная (содержащая всех родителей определенной записи) - [TA]( [ID], [ANCESTOR] ).

Запрос:

select [NAME] from T as TC
order by
(
select sum( TT.[ORDER] ) from
(
select TP.[ORDER] * power( convert( numeric, 1000 ), 11 - TP.[LEVEL] ) as [ORDER]
from TA inner join T as TP on TP.[ID] = TP.[ANCESTOR]
where TA.[ID] = TC.[ID]
) as TT
)

В таком виде будет работать, если количество уровней < 11, а элементов на уровне < 1000.
...
Рейтинг: 0 / 0
24.12.2001, 07:46
    #32019648
Иерархии с сортировкой внутри уровня.
> Я все-таки хотел узнать, нет ли варианта построения иерархии вообще без всяких глобальных апдейтов и рекурсивных движений по дереву. Добавление элемента одиночным инсертом (или двумя в разные таблицы), выборка одним запросом (пусть и сложным)
Получается нет способа?

Вот такая процедура не покажется слишком мудрёной?

CREATE PROCEDURE TreeMsg AS

declare @level int, @sublevel int
set nocount on

create table #outres (
Id int identity(1,1) not null Primary Key,
MsgId int not null Unique,
ParentId int null,
LevelNum int not null,
OrderByVal varchar(255) null,
)

while 1=1
begin
set @level=IsNull(@level,0)+1

insert into #outres (MsgId,ParentId,LevelNum)
select Id, ParentId, @level
from MessageBoard m
where (ParentId in (select MsgId from #outres) or ParentId is null)
and Id not in (select MsgId from #outres)
order by RegDate desc

if @@ROWCOUNT=0 break
end

set @sublevel=1
while @sublevel<=@level
begin

update self set OrderByVal=IsNull(parent.OrderByVal,'')+right('0000'+convert(varchar(10),self.Id),5)+'.'
from #outres self
left join #outres parent on self.ParentId=parent.MsgId
where self.LevelNum=@sublevel

set @sublevel=@sublevel+1

end

select o.MsgId, m.Title, m.RegDate, o.ParentId, o.LevelNum
from #outres o
inner join MessageBoard m on o.MsgId=m.Id
order by o.OrderByVal

GO

Для таблицы

CREATE TABLE MessageBoard (
Id int IDENTITY (1, 1) NOT NULL Primary Key,
ParentId int NULL ,
Title varchar(60) NOT NULL ,
RegDate datetime NOT NULL DEFAULT getdate(),
.....)


Обращаю ваше внимание, что первый цикл, вычисляющий номер уровня, и второй цикл, вычисляющий поле сортировки вывода дерева, производится столько раз, какая максимальная глубина вложенности дерева +1. Т.е. если максимальный уровень в дереве 10, то цикл выполниться 11 раз, что не есть много. Т.е. элементы здесь не перебираются.
...
Рейтинг: 0 / 0
24.12.2001, 13:09
    #32019688
Oleg_Martynov
Участник
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Иерархии с сортировкой внутри уровня.
С этими деревьями и у меня одна сплошная мука, по тем же причинам. Ну не поддерживаются они напрямую реляционной схемой, и всё тут. Иерархическими - поддерживаются напрямую, а реляционной - нет. С Вашего позволения, некоторые общие мысли.
Посмотрим на определения деревьев (не упорядоченных. Модификация для упорядоченных деревьев очевидна).
По определению, дерево - это узел ("корень"), который может иметь "потомков" - другие деревья. Т.е. определение в принципе рекурсивное. Чтобы обойти дерево, исходя из этого определения, можно использовать рекурсию.
Любая рекурсия может быть приведена к итерации. Тогда дерево - это структура, состоящая из корневого узла, который может быть связан с другими узлами - "потомками".Каждый узел - "потомок" может быть связан со своими узлами - "потомками", причём с любым узлом - "потомком" должен быть связан ровно один узел - предок. Чтобы обойти дерево, исходя из этого определения, можно использовать итерацию.
Попробуем по-другому. Дерево из N узлов - это матрица T(NxN), такая что 1) элемент T(i,j) = 1, если узел j является предком узла i; 2) элемент T(i,j) = 0, если узел j НЕ является предком узла i; 3) каждая строка, T(i), кроме одной, должна содержать ровно один единичный элемент 4) должна существовать единственная строка T(k), состоящая из одних нулей, и узел k - это корень дерева. С точки зрения реляционной схемы - ещё хуже, получили таблицу с переменным числом столбцов (или переменное число таблиц), и всё равно, менять нужно много элементов. Да и при выборке итерации нужны.
И т.д. Наверное, сколько существует возможных математических аппаратов - столько и определений дерева (можно, например, определить дерево неким формальным языком - и опять, магазинный автомат -> рекурсия).
Обратим внимание, что в определениях отсутствует понятие "уровень" или "номер уровня".
Реляционная схема не поддерживает рекурсии или итерации иначе, чем через расширения SQL или QBE, или ещё какого-либо реляционного языка (потому что отношение - это НЕупорядоченное множество кортежей атомарных элементов). В случае SQL эти расширения - это язык встроенных процедур/триггеров. Другими словами, SELECT реализует операции над неупорядоченными множествами кортежей, состоящих из некоторых "атомарных" элементов (по определению первой нормальной формы). Это справедливо для любого языка, действующего в рамках реляционной модели.
Что же мы должны хранить, явно или неявно, в структуре, моделирующей наше упорядоченное дерево, чтобы можно было сортировать (т.е. "обходить") дерево: 1) Ссылку на предка (явно, или например, "наоборот" - ссылкой на потомка(ов)); 2)Номер потомка (явно или неявно - например, ссылкой на предыдущего брата); 3) И, наконец, информацию, ассоциированную с узлом, из-за которой мы и строим дерево (впрочем, это к делу не относится). Если хотим "просто" делать выборки по уровням: 4) Номер уровня (явно, неявно уже хранится в 1)). Кстати, не видел ещё задачи, где бы потребовалось выбрать не "всех прямых потомков узла Х", а "все узлы 3-го уровня".
Видно, что при некоторой произвольной перестройке дерева, необходимо менять всю информацию о положении узла, а поскольку при этом меняется порядок и других узлов (т.е. их "номер при обходе дерева") - и информацию в них тоже.
- Если мы хотим делать простые выборки - нужно хранить 1), 2) явно - тогда необходимы сложные обновления. Для справочников, которые редко меняются не так и сложно, как здесь уже упоминалось. IMHO, обсуждаемая здесь идея с "предварительной нумерацией" узлов дерева мне очень понравилась (прочёл в рассылке это сайта №66) - даже завидно, как всё просто. (Ведь почти она же описана у Ахо, Ульмана и Ко в "Структурах данных..." при обсуждении деревьев - а вот не увидел...) А целостность дерева пусть обеспечивает механизм транзакций.
- Если нам нужны быстрые обновления - храним 1), 2) неявно (ссылками) - тогда при выборках без процедур не обойтись - нужна рекурсия или итерация.
Кстати, ведь в точности та же проблема и при попытке хранить списки. Список ведь тоже структура рекурсивная, и опять, простые обновления - за счёт сложной выборки. И наоборот. Правда, обновлять нужно 2 узла - но ведь не один (вставляемый-удаляемый-перемещаемый)!
Ожидать в будущем каких-то расширений SQL (именно SQL! Не языков объектно-ориентированных баз), позволяющих "просто" решить данную задачу, IMHO, не стоит - несоответствие теории даром не проходит. А нам нужен SELECT (или UPDATE), выполняющий операции не над "неупорядоченным множеством кортежей атомарных элементов", а над "множеством упорядоченных кортежей множеств".
А вдруг кто-нибудь знает другие красивые идеи по поводу моделирования деревьев в реляционной схеме (возможно, деревьев какого-либо специального вида)?
Прошу прощения за очевидные рассуждения - но с деревьями этими и правда проблема. Причём, такое впечатление, что проблема больше концептуальная, и наверняка глубже, чем я представляю. Может, из-за этих проблем и иерархические схемы БД забыты? Хотя в любой предметной области иерархию не встретить - чудо.
С уважением - Олег.
...
Рейтинг: 0 / 0
Форумы / Microsoft SQL Server [игнор отключен] [закрыт для гостей] / Иерархии с сортировкой внутри уровня. / 12 сообщений из 12, страница 1 из 1
Найденые пользователи ...
Разблокировать пользователей ...
Читали форум (0):
Пользователи онлайн (0):
x
x
Закрыть


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