Иерархию в плоское
От: Sаныч Таиланд  
Дата: 11.03.18 22:30
Оценка:
Есть таблица с ролями вида Role (Id, Parent) и таблица UserRole (User, Role). Роли могут быть иерархическими. Есть ли какой-то элегантный запрос без курсоров, чтобы получать таблицу виду FlattenUserRole (User, Role) где бы строчки по User дублировались столько раз, сколько ролей (включая родительские) имеет User.
Re: Иерархию в плоское
От: wildwind Россия  
Дата: 11.03.18 23:32
Оценка:
Здравствуйте, Sаныч, Вы писали:

S>Есть таблица с ролями вида Role (Id, Parent) и таблица UserRole (User, Role). Роли могут быть иерархическими. Есть ли какой-то элегантный запрос без курсоров, чтобы получать таблицу виду FlattenUserRole (User, Role) где бы строчки по User дублировались столько раз, сколько ролей (включая родительские) имеет User.


Это называется транзитивное замыкание. "Элегантный" запрос возможен в Oracle c его Hierarchical clause. В других СУБД с поддержкой recursive CTE запрос без курсоров тоже возможен, но назвать его элегантным уже сложно (если под элегантностью понимать лаконичность).
Re[2]: Иерархию в плоское
От: Sаныч Таиланд  
Дата: 12.03.18 07:14
Оценка:
Здравствуйте, wildwind, Вы писали:

W>Здравствуйте, Sаныч, Вы писали:


S>>Есть таблица с ролями вида Role (Id, Parent) и таблица UserRole (User, Role). Роли могут быть иерархическими. Есть ли какой-то элегантный запрос без курсоров, чтобы получать таблицу виду FlattenUserRole (User, Role) где бы строчки по User дублировались столько раз, сколько ролей (включая родительские) имеет User.


W>Это называется транзитивное замыкание. "Элегантный" запрос возможен в Oracle c его Hierarchical clause. В других СУБД с поддержкой recursive CTE запрос без курсоров тоже возможен, но назвать его элегантным уже сложно (если под элегантностью понимать лаконичность).


У нас MSSQL. Могли бы вы привести пример запроса? С CTE знаком, но больше как конструкцию для вложенных запросов. А тут нужна рекурсия.
Re: Иерархию в плоское
От: Maniacal Россия  
Дата: 12.03.18 12:47
Оценка:
Здравствуйте, Sаныч, Вы писали:

S>Есть таблица с ролями вида Role (Id, Parent) и таблица UserRole (User, Role). Роли могут быть иерархическими. Есть ли какой-то элегантный запрос без курсоров, чтобы получать таблицу виду FlattenUserRole (User, Role) где бы строчки по User дублировались столько раз, сколько ролей (включая родительские) имеет User.


Вот нашёл статейку по теме. На MS-SQL поддерживается начиная с версии MSSQL Server 2005. Если нужно, могу SQL-запрос накидать применимо конкретно к MS-SQL
Re[2]: Иерархию в плоское
От: Sаныч Таиланд  
Дата: 12.03.18 13:46
Оценка:
Здравствуйте, Maniacal, Вы писали:

M>Здравствуйте, Sаныч, Вы писали:


S>>Есть таблица с ролями вида Role (Id, Parent) и таблица UserRole (User, Role). Роли могут быть иерархическими. Есть ли какой-то элегантный запрос без курсоров, чтобы получать таблицу виду FlattenUserRole (User, Role) где бы строчки по User дублировались столько раз, сколько ролей (включая родительские) имеет User.


M>Вот нашёл статейку по теме. На MS-SQL поддерживается начиная с версии MSSQL Server 2005. Если нужно, могу SQL-запрос накидать применимо конкретно к MS-SQL


Я думаю так ровно обратное, что мне требуется. Я не хочу представлять в иерархии. Я как раз хочу сделать плоским список.
Re[3]: Иерархию в плоское
От: Olaf Россия  
Дата: 12.03.18 16:36
Оценка: 13 (2)
Здравствуйте, Sаныч, Вы писали:

S>У нас MSSQL. Могли бы вы привести пример запроса? С CTE знаком, но больше как конструкцию для вложенных запросов. А тут нужна рекурсия.


Рекурсия CTE как раз помогает развернуть иерархию в "плоский" вид. Если я правильно понял вашу задачу, то можно реализовать так. Проверьте только меня.

  Данные
create table #role(Id int, Parent int, Name varchar(30)) 
create table #user(Id int, Name varchar(30)) 
create table #userrole(UserId int, RoleId int) 

truncate table #user 
insert into #user select 1, 'Иван' 
insert into #user select 2, 'Пётр' 
insert into #user select 3, 'Сергей' 
insert into #user select 4, 'Игорь' 

truncate table #role 
insert into #role select 1, null, 'Администратор' 
insert into #role select 2, 1, 'Менеджер' 
insert into #role select 3, 1, 'Разработчик' 
insert into #role select 4, 2, 'Специалист' 
insert into #role select 5, null, 'Кассир' 

truncate table #userrole 
insert into #userrole select 1, 4 
insert into #userrole select 2, 3 
insert into #userrole select 3, 1
insert into #userrole select 4, 5


;with cte as
(
    select r.Id as RoleId, r.Parent, r.Name as Role, ur.UserId
    from #role r
    join #userrole ur on r.Id = ur.RoleId
    union all
    select r.Id as RoleId, r.Parent, r.Name, t.UserId
    from #role r
    join cte t on r.Id = t.Parent
)
select c.RoleId, c.Role, u.Id, u.Name
from cte c
join #user u on c.UserId = u.Id
order by u.Name, c.Role
Re[3]: Иерархию в плоское
От: Буравчик Россия  
Дата: 26.03.18 13:42
Оценка:
Здравствуйте, Sаныч, Вы писали:

S>>>Есть таблица с ролями вида Role (Id, Parent) и таблица UserRole (User, Role). Роли могут быть иерархическими. Есть ли какой-то элегантный запрос без курсоров, чтобы получать таблицу виду FlattenUserRole (User, Role) где бы строчки по User дублировались столько раз, сколько ролей (включая родительские) имеет User.


M>>Вот нашёл статейку по теме. На MS-SQL поддерживается начиная с версии MSSQL Server 2005. Если нужно, могу SQL-запрос накидать применимо конкретно к MS-SQL


S>Я думаю так ровно обратное, что мне требуется. Я не хочу представлять в иерархии. Я как раз хочу сделать плоским список.


Если бы данные о ролях хранились бы не в виде Parent-Child, а в виде Nested Sets, то такие запросы делались бы очень легко (без рекурсии)
Best regards, Буравчик
Re[4]: Иерархию в плоское
От: Somescout  
Дата: 26.03.18 19:03
Оценка:
Здравствуйте, Буравчик, Вы писали:

Б>Если бы данные о ролях хранились бы не в виде Parent-Child, а в виде Nested Sets, то такие запросы делались бы очень легко (без рекурсии)


Они и так делаются легко с помощью CTE. А nested sets требуют дополнительной поддержки при обновлении таблицы.
ARI ARI ARI... Arrivederci!
 
Подождите ...
Wait...
Пока на собственное сообщение не было ответов, его можно удалить.