use AnP

if object_id(N'dbo.groups_tables_delete', N'P') is not null drop procedure dbo.groups_tables_delete
go
create procedure dbo.groups_tables_delete as begin 

    set nocount on;

    -- Level 3.
    if object_id(N'dbo.GroupsIps', N'U') is not null drop table dbo.GroupsIps
    if object_id(N'dbo.GroupsUsers', N'U') is not null drop table dbo.GroupsUsers

    -- Level 1.
    if object_id(N'dbo.Groups', N'U') is not null drop table dbo.Groups

    -- Level 0.
    if object_id(N'dbo.GroupsTypes', N'U') is not null drop table dbo.GroupsTypes

    -- Level historical.
    if object_id(N'dbo.GroupsIpsData', N'U') is not null drop table dbo.GroupsIpsData
    if object_id(N'dbo.GroupsUsersData', N'U') is not null drop table dbo.GroupsUsersData
    if object_id(N'dbo.GroupsData', N'U') is not null drop table dbo.GroupsData
    if object_id(N'dbo.GroupsTypesData', N'U') is not null drop table dbo.GroupsTypesData

end
go

if object_id(N'dbo.groups_tables_create', N'P') is not null drop procedure dbo.groups_tables_create
go
create procedure dbo.groups_tables_create as begin 

    set nocount on;

    -- Level historical.
    if object_id(N'dbo.GroupsTypesData', N'U') is null create table dbo.GroupsTypesData(
        id integer not null identity(1,1), 
        entity integer not null,
        [name] varchar(32) not null,
        [description] varchar(256),
        date_in datetime not null,
        date_out datetime, 
        constraint pk_groups_types primary key clustered(id)
    )

    if object_id(N'dbo.GroupsData', N'U') is null create table dbo.GroupsData(
        id integer not null identity(1,1), 
        entity integer not null, 
        [procedure] integer not null, 
        [session] integer not null, 
        [type] integer not null, 
        [name] varchar(32) not null,
        [description] varchar(256),
        date_in datetime not null,
        date_out datetime,
        constraint pk_groups_data primary key clustered (id)
    )

    if object_id(N'dbo.GroupsIpsData', N'U') is null create table dbo.GroupsIpsData(
        id integer not null identity(1,1), 
        entity integer not null,
        [procedure] integer not null, 
        [session] integer not null, 
        [group] integer not null, 
        [ip] integer not null,
        belongs bit not null,
        date_in datetime not null,
        constraint pk_groups_ips_data primary key clustered (id)
    )

    if object_id(N'dbo.GroupsUsersData', N'U') is null create table dbo.GroupsUsersData(
        id integer not null identity(1,1), 
        entity integer not null,
        [procedure] integer not null, 
        [session] integer not null, 
        [group] integer not null, 
        [user] integer not null,
        belongs bit not null,
        date_in datetime not null,
        constraint pk_groups_users_data primary key clustered (id)
    )

    -- Level 0.
    if object_id(N'dbo.GroupsTypes', N'U') is null create table dbo.GroupsTypes(
        id integer not null identity(1,1), 
        [name] varchar(32) not null,
        [description] varchar(256),
        date_in datetime not null constraint df_groups_types_date_in default getdate(),
        date_out datetime, 
        constraint pk_groups_types primary key clustered (id), 
        constraint uk_groups_types_name unique nonclustered ([name] asc) with (fillfactor = 90), 
        constraint ck_groups_types_name check ([name] != '')
    )

    -- Level 1.
    if object_id(N'dbo.Groups', N'U') is null begin 
        create table dbo.Groups(
            id integer not null identity(1,1), 
            [type] integer not null,
            [name] varchar(32) not null,
            [description] varchar(256),
            date_in datetime not null constraint df_groups_date_in default getdate(),
            date_out datetime,
            constraint pk_groups primary key clustered (id), 
            constraint fk_groups_type foreign key ([type]) references dbo.GroupsTypes(id), 
            constraint uk_groups_type_name unique([name], [type]),
            constraint ck_groups_type check ([type] > 0),
            constraint ck_groups_name check ([name] != '')
        )
        create nonclustered index ix_groups_type on dbo.Groups([type] asc) include ([name]) with (fillfactor = 90)
        create nonclustered index ix_groups_name on dbo.Groups([name] asc) include ([type]) with (fillfactor = 90)
    end

    -- Level 2.
    if object_id(N'dbo.GroupsIps', N'U') is null begin 
        create table dbo.GroupsIps(
            id integer not null identity(1,1), 
            [group] integer not null, 
            [ip] integer not null,
            belongs bit not null constraint df_groups_ips_belongs default 1,
            date_in datetime not null constraint df_groups_ips_date_in default getdate(),
            constraint pk_groups_ips primary key clustered (id), 
            constraint fk_groups_ips_group foreign key ([group]) references dbo.Groups(id),
            constraint fk_groups_ips_ip foreign key ([ip]) references dbo.Ips(id), 
            constraint uk_groups_ips_group_ip unique([group], [ip]), 
            constraint ck_groups_ips_group check ([group] > 0), 
            constraint ck_groups_ips_ip check ([ip] > 0)
        )
        create nonclustered index ix_groups_ips_group on dbo.GroupsIps([group] asc) include ([ip], belongs) with (fillfactor = 90)
        create nonclustered index ix_groups_ips_ip on dbo.GroupsIps([ip] asc) include ([group], belongs) with (fillfactor = 90)
    end

    if object_id(N'dbo.GroupsUsers', N'U') is null begin 
        create table dbo.GroupsUsers(
            id integer not null identity(1,1), 
            [group] integer not null, 
            [user] integer not null,
            belongs bit not null constraint df_groups_users_belongs default 1,
            date_in datetime not null constraint df_groups_users_date_in default getdate(),
            constraint pk_groups_users primary key clustered (id), 
            constraint fk_groups_users_group foreign key ([group]) references dbo.Groups(id),
            constraint fk_groups_users_user foreign key ([user]) references dbo.Users(id), 
            constraint uk_groups_users_group_user unique([group], [user]), 
            constraint ck_groups_users_group check ([group] > 0), 
            constraint ck_groups_users_user check ([user] > 0)
        )
        create nonclustered index ix_groups_users_group on dbo.GroupsUsers([group] asc) include ([user], belongs) with (fillfactor = 90)
        create nonclustered index ix_groups_users_user on dbo.GroupsUsers([user] asc) include ([group], belongs) with (fillfactor = 90)
    end

end
go

if object_id(N'dbo.groups_tables_update', N'P') is not null drop procedure dbo.groups_tables_update
go
create procedure dbo.groups_tables_update as begin 

    set nocount on;

end
go

execute dbo.groups_tables_delete
go
execute dbo.groups_tables_create
go
execute dbo.groups_tables_update
go

if object_id(N'dbo.groups_trigger_update', N'TR') is not null drop trigger dbo.groups_trigger_update
go
create trigger dbo.groups_trigger_update on dbo.Groups after insert, update as begin 

    declare @database varchar(64)
    declare @procedure varchar(64)
    declare @procedure_id integer
    declare @session integer
    declare @id integer
    declare @name varchar(32)
    declare @description varchar(256)
    declare @date_in datetime
    declare @date_out datetime
    declare groups_cursor cursor local for (
        select id, [name], [description], date_in, date_out from inserted
    )

    set nocount on

    execute dbo.sql_get @database output, @procedure output, @session output
    execute dbo.procedure_get @database, @procedure, @procedure_id output

    open groups_cursor
    while 1 = 1 begin
        fetch next from groups_cursor into @id, @procedure, @session, @name, @description, @date_in, @date_out
        if @@fetch_status != 0 
            break
        insert into dbo.GroupsData(entity, [procedure], [session], [name], [description], date_in, date_out) values 
            (@id, @procedure, @session, @name, @description, @date_in, @date_out)
        update dbo.Groups set data_id = scope_identity() where id = @id
    end
    close groups_cursor
    deallocate groups_cursor

end
go

if object_id(N'dbo.groups_ips_trigger_update', N'TR') is not null drop trigger dbo.groups_ips_trigger_update
go
create trigger dbo.groups_ips_trigger_update on dbo.GroupsIps after insert, update as begin 

    declare @database varchar(64)
    declare @procedure varchar(64)
    declare @procedure_id integer
    declare @session integer
    declare @id integer
    declare @group integer
    declare @ip integer
    declare @belongs bit
    declare @date_in datetime
    declare groups_ips_cursor cursor local for (
        select id, [group], [ip], belongs, date_in from inserted
    )

    set nocount on

    execute dbo.sql_get @database output, @procedure output, @session output
    execute dbo.procedure_get @database, @procedure, @procedure_id output

    open groups_ips_cursor
    while 1 = 1 begin
        fetch next from groups_ips_cursor into @id, @group, @ip, @belongs, @date_in
        if @@fetch_status != 0 
            break
        insert into dbo.GroupsIpsData(entity, [procedure], [session], [group], [ip], belongs, date_in) values 
            (@id, @procedure_id, @session_id, @group, @ip, @belongs, @date_in)
    end
    close groups_ips_cursor
    deallocate groups_ips_cursor

end
go

if object_id(N'dbo.groups_users_trigger_update', N'TR') is not null drop trigger dbo.groups_users_trigger_update
go
create trigger dbo.groups_users_trigger_update on dbo.GroupsUsers after insert, update as begin 

    declare @database varchar(64)
    declare @procedure varchar(64)
    declare @procedure_id integer
    declare @session integer
    declare @id integer
    declare @group integer
    declare @user integer
    declare @belongs bit
    declare @date_in datetime
    declare groups_users_cursor cursor local for (
        select id, [group], [user], belongs, date_in from inserted
    )

    set nocount on

    execute dbo.sql_get @database output, @procedure output, @session output
    execute dbo.procedure_get @database, @procedure, @procedure_id output

    open groups_users_cursor
    while 1 = 1 begin
        fetch next from groups_users_cursor into @id, @procedure, @session, @group, @user, @belongs, @date_in
        if @@fetch_status != 0 
            break
        insert into dbo.GroupsUsersData(entity, [procedure], [session], [group], [user], belongs, date_in) values 
            (@id, @procedure, @session, @group, @user, @belongs, @date_in)
        update dbo.GroupsUsers set data_id = scope_identity() where id = @id
    end
    close groups_users_cursor
    deallocate groups_users_cursor

end
go

execute dbo.groups_tables_fill
go

if object_id(N'dbo.IpsView', N'V') is not null drop view dbo.IpsView
go
create view dbo.IpsView as select 
    ips.id as id,
    ips.[ip] as [ip],
    ips.date_in as date_in
from dbo.Ips ips 
where ips.date_out is null
go

if object_id(N'dbo.UsersView', N'V') is not null drop view dbo.UsersView
go
create view dbo.UsersView as select 
    users.id as id,
    users.nick as nick,
    users.date_in as date_in
from dbo.Users users 
where users.date_out is null
go

if object_id(N'dbo.GroupsView', N'V') is not null drop view dbo.GroupsView
go
create view dbo.GroupsView as select 
    groups.id as id,
    groups.name as [name],
    groups.description as [description], 
    groups.date_in as date_in
from dbo.Groups groups 
where groups.date_out is null
go

if object_id(N'dbo.GroupsIpsView', N'V') is not null drop view dbo.GroupsIpsView
go
create view dbo.GroupsIpsView as select 
    groups_ips.id as id,
    groups.id as group_id,
    groups.[name] as [group], 
    ips.id as ip_id, 
    ips.[ip] as [ip], 
    isnull(groups_ips.belongs, 0) as belongs,
    groups_ips.date_in as date_in
from dbo.GroupsViews groups 
join dbo.IpsViews ips on 1 = 1
left join dbo.GroupsIps groups_ips on 
    groups_ips.[group] = groups.id 
    groups_ips.[ip] = ips.id 
go

if object_id(N'dbo.GroupsUsersView', N'V') is not null drop view dbo.GroupsUsersView
go
create view dbo.GroupsUsersView as select 
    groups_users.id as id,
    groups.id as group_id,
    groups.[name] as [group], 
    users.id as user_id, 
    users.nick as [user], 
    isnull(groups_users.belongs, 0) as belongs,
    groups_users.date_in as date_in
from dbo.GroupsViews groups 
join dbo.UsersViews users on 1 = 1
left join dbo.GroupsUsers groups_users on 
    groups_users.[group] = groups.id 
    groups_users.[user] = users.id 
go