powered by simpleCommunicator - 2.0.61     © 2026 Programmizd 02
Целевая тема:
Создать новую тему:
Автор:
Закрыть
Цитировать
Форумы / Проектирование БД [игнор отключен] [закрыт для гостей] / Иерархия
14 сообщений из 39, страница 2 из 2
Иерархия
    #36116998
Naf
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
улучшил:
Код: plaintext
1.
2.
3.
4.
5.
6.
7.
8.
9.
10.
11.
12.
13.
14.
15.
16.
17.
18.
19.
20.
21.
22.
23.
SELECT 
G1.ID ID ,G1.NAME NAME, 
      SUM(
      CASE WHEN G1.LEFTBOUND BETWEEN G2.LEFTBOUND AND G2.RIGHTBOUND THEN  1 
           ELSE  0 
      END) LEV
FROM GOOD G1
LEFT JOIN GOOD G2 ON NOT(G1.ID=G2.ID)
LEFT JOIN GOOD GI1 ON (G1.LEFTBOUND BETWEEN GI1.LEFTBOUND AND GI1.RIGHTBOUND)
LEFT JOIN GOOD GI2 ON (G2.LEFTBOUND BETWEEN GI2.LEFTBOUND AND GI2.RIGHTBOUND)
WHERE
     ((GI1.PARENT=GI2.PARENT) OR ((GI1.PARENT IS NULL)AND(GI2.PARENT IS NULL))) AND
     (NOT(GI1.ID=GI2.ID) OR (G1.ID=GI1.ID) OR (G2.ID=GI2.ID))   
GROUP BY G1.ID, G1.NAME
ORDER BY
     SUM( 
     CASE
       WHEN G2.LEFTBOUND BETWEEN G1.LEFTBOUND AND G1.RIGHTBOUND THEN  1 
       WHEN G1.LEFTBOUND BETWEEN G2.LEFTBOUND AND G2.RIGHTBOUND THEN  0 
       WHEN (GI1.ISGROUP>GI2.ISGROUP) THEN  1 
       WHEN (GI1.ISGROUP<GI2.ISGROUP) THEN  0         
       WHEN (GI1.NAME<GI2.NAME) THEN  1         
       ELSE  0 
     END) DESC
С уважением, Naf
...
Рейтинг: 0 / 0
Иерархия
    #36117474
Naf
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
Наконец, допустим есть таблица продаж (очень упрощенно)
Код: plaintext
1.
2.
3.
4.
5.
6.
CREATE TABLE SALE (
       ID Integer NOT NULL,
       GOOD Integer NOT NULL,
       ACOUNT Numeric( 15 , 3 ) NOT NULL,
       CONSTRAINT PK_SALE PRIMARY KEY (ID)
);
ALTER TABLE SALE ADD CONSTRAINT FK_SALE_1 FOREIGN KEY (GOOD) REFERENCES GOOD(ID);
И нам необходимо вывести продаваемые продукты по-иерархии с требуемой сортировкой:
Код: 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.
SELECT T.ID ID ,T.NAME NAME, T.LEV LEV, SUM(S.ACOUNT) ACOUNT
FROM SALE S
INNER JOIN GOOD G ON (S.GOOD=G.ID)
INNER JOIN
(SELECT 
G1.ID ID ,G1.NAME NAME, G1.LEFTBOUND LEFTBOUND, G1.RIGHTBOUND RIGHTBOUND, 
      SUM(
      CASE WHEN G1.LEFTBOUND BETWEEN G2.LEFTBOUND AND G2.RIGHTBOUND THEN  1 
           ELSE  0 
      END) LEV,
     SUM( 
     CASE
       WHEN G2.LEFTBOUND BETWEEN G1.LEFTBOUND AND G1.RIGHTBOUND THEN  1 
       WHEN G1.LEFTBOUND BETWEEN G2.LEFTBOUND AND G2.RIGHTBOUND THEN  0 
       WHEN (GI1.ISGROUP>GI2.ISGROUP) THEN  1 
       WHEN (GI1.ISGROUP<GI2.ISGROUP) THEN  0         
       WHEN (GI1.NAME<GI2.NAME) THEN  1         
       ELSE  0 
     END) ORD
FROM GOOD G1
LEFT JOIN GOOD G2 ON NOT(G1.ID=G2.ID)
LEFT JOIN GOOD GI1 ON (G1.LEFTBOUND BETWEEN GI1.LEFTBOUND AND GI1.RIGHTBOUND)
LEFT JOIN GOOD GI2 ON (G2.LEFTBOUND BETWEEN GI2.LEFTBOUND AND GI2.RIGHTBOUND)
WHERE
     ((GI1.PARENT=GI2.PARENT) OR ((GI1.PARENT IS NULL)AND(GI2.PARENT IS NULL))) AND
     (NOT(GI1.ID=GI2.ID) OR (G1.ID=GI1.ID) OR (G2.ID=GI2.ID))   
GROUP BY G1.ID, G1.NAME, G1.LEFTBOUND, G1.RIGHTBOUND) T 
      ON ((G.ID=T.ID) OR (G.LEFTBOUND BETWEEN T.LEFTBOUND AND T.RIGHTBOUND))
GROUP BY T.ID,T.NAME,T.LEV, T.ORD      
ORDER BY T.ORD DESC
С уважением, Naf
...
Рейтинг: 0 / 0
Иерархия
    #36117955
Фотография ChA
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
Nafесть табличка, типа есть группы в них группы или товары (как файлы-папки)Не самая подходящая аналогия, IMHO. Не стоит смешивать группы и товары в одной таблице. Этим, как минимум, усложняется проверка корректности данных. Например, группа может оказаться потомком товара, да и иерархичность товара вызывает сомнения.

Хранение иерархии "методом Селко" может показаться привлекательным чисто теоретически, но, как показала практика, он больше вызывает проблем, чем их решает. Разумеется, никто не может помешать проверить это утверждение самому. Какой метод выбрать взамен него, трудно сказать однозначно. Для некоторых задач вполне достаточно стандартной пары (ID, ParentID) и рекурсивных запросов.

Иерархия групп товаров - вещь, как минимум, очень неудобная, хотя бы по причине "жёсткости". В данном случае, IMHO, стоило бы применить "теговый" подход, когда к товару можно "прицепить" какие угодно теги, каждый из которых представляет собой ссылку на некий классификатор, в том числе и иерархический, если возникнет острая необходимость. Т.е., классический вариант связи M:N, реализованный через дополнительную таблицу, где с одной стороны товары, а с другой - теги(ссылки на классификаторы). Такой подход позволит строить "визуальные" иерархии, наиболее уместные в конкретной ситуации или для конкретного пользователя простым выбором последовательности тегов. Например, сначала по производителям, а потом по видам продукции, а можно наоборот, сначала по видам продукции, а потом по производителям.

P.S. Хотелось бы отметить, что на практике, IMHO, часто тяготеют к иерархическим структурам, где их наличие совершенно неоправданно. "Истинных" иерархий, подобно генеалогическому дереву, на практике не так уж и много. В таких случаях обычно подразумеваются, что все элементы этой иерархии однотипны.
...
Рейтинг: 0 / 0
Иерархия
    #36168878
Фотография Roman S. Golubin
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
ChAХранение иерархии "методом Селко" может показаться привлекательным чисто теоретически, но, как показала практика, он больше вызывает проблем, чем их решает.
Хмм... голословное утверждение. Знаю как минимум два случая из личной практики, когда применение метода Селко избавило от необходимости приобретения дорогущего железа. При этом сложность добавления/удаления/изменения данных для процедур, которые с этим деревом работали, ни как не изменилась. Вместо корявых и медленных циклов / курсоров / CTE для выборки данных из деревянной структуры, были написаны однопроходные запросы и построены индексы. При этом, скорость работы увеличилась на несколько порядков, а нагрузка на железо упала в несколько раз.
...
Рейтинг: 0 / 0
Иерархия
    #36168923
Фотография ChA
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
Roman S. Golubinголословное утверждение.Роман, могу ответить в том же духе, твои примеры тоже являются голословным утверждением. Дабы избегать ненужного эпатажа и сосредоточиться на сути, предлагаю в дальнейшем исключить подобные формулировки. Мои утверждения основаны на моей практике, твои на твоей, давай исходить из этого.
Roman S. GolubinЗнаю как минимум два случая из личной практики, когда применение метода Селко избавило от необходимости приобретения дорогущего железа. При этом сложность добавления/удаления/изменения данных для процедур, которые с этим деревом работали, ни как не изменилась.Разумеется, если использовать метод вложенных множеств(Селко) в качестве альтернативы дилетантским решениям, то не исключаю, что он может выиграть по некоторым пунктам. Но от его родового проклятия, пересчёта и модификации LR-значений, в среднем затрагивающих до половины узлов дерева, увы, не избавиться.
Если использовать большую разреженность значений, чтобы снизить объем модификаций, то мы теряем некоторые преимущества, которые даёт непрерывность LR-последовательности, при этом дополнительная проверка на предмет нахождения внутри псевдофиксированных границ остаётся.
Даже для простейшего поиска всех потомков узла необходимо использовать слияние, для получения по идентификатору узла его LR-значений, чтобы выбрать потомков, чьи LR-значения находятся внутри LR-границ предка. Причем сами LR-значения мы не можем использовать в качестве ключа в связи с их потенциальной изменчивостью.
Поиск всех предков листа приводит к сканированию всех узлов дерева, что с учётом потенциальной перестройки дерева при модификации может породить немало проблем. То же самое произойдёт при попытке вычислить уровень листа.
Слишком часто используется between, что мешает использованию merge- и hash-алгоритмов при различных выборках. Да и с индексом есть проблемы, так как у нас для каждого узла есть 2 совершенно независимых друг от друга значения. В результате, польза от индекса (L,R) невелика, а использование 2 отдельных индексов по L и R сервером запросто игнорируется с точки зрения IO. Дешевле сделать seek+scan по какому-либо одному из них.
Roman S. GolubinВместо корявых и медленных циклов / курсоров / CTE для выборки данных из деревянной структуры, были написаны однопроходные запросы и построены индексы. При этом, скорость работы увеличилась на несколько порядков, а нагрузка на железо упала в несколько раз.Я тоже видел много ужасных реализаций, но это говорит лишь об уровне их авторов. Тем более, что ты упомянул создание индексов, исключение курсоров. Так зачем же противопоставлять заведомо плохую реализацию работы с деревом и метод вложенных множеств, который при реализации тем же программистом мог бы точно так же, если не хуже, похоронить сервер ?
Цикла в случае стандартных (ID, ParentID) может и не избежать, но без курсоров можно запросто обойтись, этот способ был предложен в BOL еще к MS SQL версии 4.21. Почти уверен, что нормальная реализация такого подхода не сильно бы уступала методу вложенных множеств.
В случае неглубоких деревьев(2-3 уровня, что нередко бывает на практике) не думаю, что CTE принципиально проигрывает методу вложенных множеств при "правильных" индексах. Впрочем, это моё голословное, умозрительное, утверждение, сам экспериментов не ставил. Если есть обратная статистика, а ещё лучше, воспроизводимый пример, то был бы рад ознакомиться.

IMO, метод вложенных множеств может использоватся в случае не очень больших и редкоизменяющихся деревьев. Лично я исключил его из своей практики, предпочитаю развёртывание иерархии в дополнительных полях и/или таблицах.
...
Рейтинг: 0 / 0
Иерархия
    #36168936
Фотография Roman S. Golubin
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
ChA,

По поводу использования LR в качестве ключа - это жестко :) Я использовал все ту же старую модель ID/ParentID в связке с LR - индекс позволяет выбрать пару с помощью Seek. И да, в обоих случаях имелось очень большое, основательно развлетвленное и не очень активно (примерно 2-3 раза в час) изменяющееся дерево, управление структурой которого было отдано пользователям. При этом затык производительности был именно на получении потомков / путей к корню - множество поисковых запросов через web.
Перед началом перехода на метод Селко рядом стоял костыль в виде отдельного сервера Oracle, на котором курсоры (по непонятной мне причине - ни разу не пользовался ораклом ) работали на порядок быстрее, чем на MS SQL. На этом оракле и крутилось дерево.
На счет ужасности реализации - не знаю, как все это было реализовано до того, как перестало хватать железа и был установлен оракловый сервер - история об этом умалчивает :)
...
Рейтинг: 0 / 0
Иерархия
    #36173126
Борис Бритва
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
а вы еще добавте одно поле "уровень иерархии", оно может и лишнее но поможет Вам и сейчас и в будующем.

CREATE TABLE GOOD ( --товары
ID Integer NOT NULL, --первичный ключ
LEFTBOUND Integer NOT NULL,
RIGHTBOUND Integer NOT NULL,
PARENT Integer,--сылка на группу владельца, для первого уровня NULL
NAME Varchar(50) NOT NULL, --наименование группы или товара
ISGROUP Integer NOT NULL --признак группы: 0,1

LEVEL Integer NOT NULL
);
...
Рейтинг: 0 / 0
Иерархия
    #36173174
Naf
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
Борис Бритваа вы еще добавте одно поле "уровень иерархии", оно может и лишнее но поможет Вам и сейчас и в будующем.

CREATE TABLE GOOD ( --товары
ID Integer NOT NULL, --первичный ключ
LEFTBOUND Integer NOT NULL,
RIGHTBOUND Integer NOT NULL,
PARENT Integer,--сылка на группу владельца, для первого уровня NULL
NAME Varchar(50) NOT NULL, --наименование группы или товара
ISGROUP Integer NOT NULL --признак группы: 0,1

LEVEL Integer NOT NULL
);возможно, но в тоже время оно легко вычисляется
...
Рейтинг: 0 / 0
Иерархия
    #36174278
Борис Бритва
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
Naf,

c таким же успехом Вы можетесказать, что поля PARENT и ISGROUP - излишества) и вообще табличку надо нормализовать)
Вам не кажется что для таких запрросов используется подход, который позволяет оптимизировать время выполнения запроса, и позволяет строить интутивно понятные с первого взгляда простые запосы.
Представляете себе запрос такого вида как Вы предложили хотя бы для 5 измерений? =)
...
Рейтинг: 0 / 0
Иерархия
    #36174384
Борис Бритва
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
Подумайте, может Вам в условии JOIN юзать BETWEEN и тогда будет удобней?

SELECT
GOOD.NAME,
SUM( SALE.AMOUNT ) AS AMOUNT
FROM
GOOD
LEFT OUTER JOIN
SALE
ON ( SALE.GOOD BETWEEN GOOD.LEFTBOUND AND GOOD.RIGHTBOUND)
GROUP BY GOOD.NAME
ORDER BY GOOD.LEFTBOUND
...
Рейтинг: 0 / 0
Иерархия
    #36174962
Naf
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
Борис БритваNaf,

c таким же успехом Вы можетесказать, что поля PARENT и ISGROUP - излишества) и вообще табличку надо нормализовать)
Вам не кажется что для таких запрросов используется подход, который позволяет оптимизировать время выполнения запроса, и позволяет строить интутивно понятные с первого взгляда простые запосы.
Представляете себе запрос такого вида как Вы предложили хотя бы для 5 измерений? =)нормализовать можно, но денормализация специально внесена для ускорения выборок
...
Рейтинг: 0 / 0
Иерархия
    #36174966
Naf
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
Борис БритваПодумайте, может Вам в условии JOIN юзать BETWEEN и тогда будет удобней?

SELECT
GOOD.NAME,
SUM( SALE.AMOUNT ) AS AMOUNT
FROM
GOOD
LEFT OUTER JOIN
SALE
ON ( SALE.GOOD BETWEEN GOOD.LEFTBOUND AND GOOD.RIGHTBOUND)
GROUP BY GOOD.NAME
ORDER BY GOOD.LEFTBOUNDмне не нужны все товары, а только которые есть в SALE. Да и сортировки требуемой нет
...
Рейтинг: 0 / 0
Иерархия
    #36175086
Борис Бритва
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
Naf,

у меня с сортировкой все в порядке. Может у Вас в данных неправильно указаны левые и правые границы?
...
Рейтинг: 0 / 0
Иерархия
    #36175200
Naf
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
Борис Бритва,

я про ту сортировку, ради которой весь топик заводился
...
Рейтинг: 0 / 0
14 сообщений из 39, страница 2 из 2
Форумы / Проектирование БД [игнор отключен] [закрыт для гостей] / Иерархия
Найденые пользователи ...
Разблокировать пользователей ...
Читали форум (0):
Пользователи онлайн (0):
x
x
Закрыть


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