Re: Деpево

From
Миклашевич Антон (2:5020/400)
To
Vladimir Eremin (2:5054/37.63)
Date
2005-02-11T07:31:10Z
Area
SU.DBMS.SQL
From: "Миклашевич Антон" <666@kamtel.ru>

Hello, Vladimir!
You wrote to Миклашевич Антон on Thu, 10 Feb 2005 23:22:50 +0300:

      МА>>  одна таблица, подробности попробуй поискать в инете. Накрайняк 
могу
      запостить код для MS SQL.
      VE>  Может в эху... Может быть еще кому понадобится... :)


Этта я и имел ввиду. Если к табличке будет цеплятся
другая табличка внешним ключом, в прицепляемой таблице кластерным делаем
индекс по полю внешнего ключа. Вставка, модификация, удаление -
осуществляется стандартными SQL операторами.

Выборка всех потомков (прямых и косвенных) осуществляется:

select
    *
from
    НечтоГруппыТЗ гтз
        inner join
    НечтоГруппы нг
            on
                гтз.Дочерний = нг.Ид
where
    гтз.Родитель = <Ид того, чьи потомки нам нужны>


Вот собственно и само дерево:


CREATE TABLE [НечтоГруппы] (
    [Ид] uniqueidentifier PRIMARY KEY CLUSTERED,
    [ИдРодителя] uniqueidentifier NULL,
    CONSTRAINT [CK_НечтоГруппы.Ид.ИдРодителя] CHECK ([Ид] <> [ИдРодителя])
)
GO

CREATE TABLE [НечтоГруппыТЗ] (
    [Родитель] uniqueidentifier NULL ,
    [Дочерний] uniqueidentifier NOT NULL,
    CONSTRAINT [куинд_НечтоГруппыТЗ.Родитель.Дочерний] UNIQUE  CLUSTERED
    (
        [Родитель],
        [Дочерний]
    )
)
GO

ALTER TABLE [НечтоГруппы] ADD
    CONSTRAINT [вк_НечтоГруппы.Ид__НечтоГруппы.ИдРодителя] FOREIGN KEY
    (
        [ИдРодителя]
    ) REFERENCES [dbo].[НечтоГруппы] (
        [Ид]
    )
GO

ALTER TABLE [dbo].[НечтоГруппыТЗ] ADD
    CONSTRAINT [вк_НечтоГруппы.Ид__НечтоГруппыТЗ.Дочерний] FOREIGN KEY
    (
        [Дочерний]
    ) REFERENCES [dbo].[НечтоГруппы] (
        [Ид]
    ) ON DELETE CASCADE ,
    CONSTRAINT [вк_НечтоГруппы.Ид__НечтоГруппыТЗ.Родитель] FOREIGN KEY
    (
        [Родитель]
    ) REFERENCES [dbo].[НечтоГруппы] (
        [Ид]
    )
GO

SET QUOTED_IDENTIFIER ON
GO
SET ANSI_NULLS ON
GO
create trigger НечтоГруппы_ТЗ_Апдейт on dbo.НечтоГруппы
--# with encryption
after update
as begin
    set nocount on

    -- Если модифицировали Ид родителя
    if update(ИдРодителя) begin
        -- Удалим все записи об обновленных группах и их потомках
        delete
            НечтоГруппыТЗ
        from
            НечтоГруппыТЗ гтз
                inner join
            (select
                гтз1.Родитель,
                гтз1.Дочерний
            from
                НечтоГруппыТЗ гтз1
                    inner join
                deleted уд
                        on
                            гтз1.Родитель = уд.Ид
            ) as гтз2
                on
                    гтз.Дочерний = гтз2.Дочерний

        declare @tInsert table(
            Ид uniqueidentifier primary key,
            ИдРодителя uniqueidentifier null
        )
        declare @tInserted table(
            Ид uniqueidentifier primary key
        )

        insert
            НечтоГруппыТЗ(
                Родитель,
                Дочерний
            )
        select
            null,
            вст.Ид
        from
            @tInsert as вст
        where
            вст.ИдРодителя is null

        insert
            @tInsert(
                Ид,
                ИдРодителя
            )
        select
            вст.Ид,
            вст.ИдРодителя
        from
            inserted as вст

        while @@rowcount > 0 begin
            insert
                НечтоГруппыТЗ(
                    Родитель,
                    Дочерний
                )
            select
                тз.Родитель,
                вст.Ид
            from
                @tInsert as вст
                    inner join
                НечтоГруппыТЗ as тз
                        on
                            вст.ИдРодителя = тз.Дочерний

            insert
                НечтоГруппыТЗ(
                    Родитель,
                    Дочерний
                )
            select
                вст.Ид,
                вст.Ид
            from
                @tInsert as вст

            insert
                @tInserted(
                    Ид
                )
            select
                Ид
            from
                @tInsert

            delete
                @tInsert

            insert
                @tInsert(
                    Ид,
                    ИдРодителя
                )
            select
                тг.Ид,
                тг.ИдРодителя
            from
                НечтоГруппы as тг
                    inner join
                @tInserted as вст
                        on
                            тг.ИдРодителя = вст.Ид

            delete
                @tInserted

        end -- while @@rowcount > 0
    end -- if update(ИдРодителя)
end
GO

SET QUOTED_IDENTIFIER ON
GO
SET ANSI_NULLS ON
GO
create trigger НечтоГруппы_ТЗ_Вставка on dbo.НечтоГруппы
--# with encryption
after insert
as begin
    set nocount on

    -- Для корневых элементов вставляем замыкание на корень - на null,
    --  а для дочерних само будет вставляться
    insert
        НечтоГруппыТЗ(
            Родитель,
            Дочерний
        )
    select
        null,
        вст.Ид
    from
        inserted as вст
    where
        вст.ИдРодителя is null

    -- Вставляем ссылки всех родителей на новые дочерние элементы
    insert
        НечтоГруппыТЗ(
            Родитель,
            Дочерний
        )
    select
        тз.Родитель,
        вст.Ид
    from
        inserted as вст
            inner join
        НечтоГруппыТЗ as тз
                on
                    вст.ИдРодителя = тз.Дочерний

    -- Вставляем замыкание на себя
    insert
        НечтоГруппыТЗ(
            Родитель,
            Дочерний
        )
    select
        вст.Ид,
        вст.Ид
    from
        inserted as вст

end
GO 


--- ifmail v.2.15dev5.3
 * Origin: Demos online service (2:5020/400)
SEEN-BY: 46/50 50/203 520 450/159 186 1024 451/30 454/9 461/43 132 640 469/999
SEEN-BY: 4614/20 4616/3 4625/8 4627/10 5000/76 5000 5001/5001 5006/1 5007/1
SEEN-BY: 5010/53 70 5011/13 5012/23 5015/10 5019/31 5020/52 118 175 194 400
SEEN-BY: 5020/545 604 639 715 758 892 894 1042 1057 1200 1523 1604 1665 1909
SEEN-BY: 5020/1922 2013 2020 2238 4441 8383 12000 5021/29 5025/3 750 5026/10
SEEN-BY: 5026/14 45 5027/16 5029/32 5030/115 217 473 556 966 1063 1339 1900
SEEN-BY: 5031/47 5035/38 5036/1 34 5040/47 5042/13 5047/43 5049/1 5051/15
SEEN-BY: 5054/1 8 9 10 28 35 37 45 63 67 5055/95 5057/1 5059/37 5060/88
SEEN-BY: 5061/15 5062/1 5066/18 5069/7 5070/1222 5079/23 5080/68 1003 5081/2
SEEN-BY: 5082/6 5083/21 5084/32 5085/13 5090/106 5092/1 5099/133 6000/12 254
SEEN-BY: 6009/1
PATH: 5020/400 4441 545 5054/1 37