Добро пожаловать в форум, Guest  >>   Войти | Регистрация | Поиск | Правила | В избранное | Подписаться
Все форумы / Microsoft SQL Server Новый топик    Ответить
 Подскажите с запросом )  [new]
Кифирчик
Member

Откуда: СПб
Сообщений: 935
исходные данные - таблица с документами, каждый может относиться к трем member-ам.
каждый мембер - может иметь пару ролей
пытаюсь родить код, который по имени мембера может выдать нужные набор "документов"
проблема в том, что если мы выбираем для ролей А и Б, то допустимо чтоб memberC_id is null
также, если у мембера 2 роли - то фильтры должны как-то плюсоваться

очень не хочется делать динамический SQL
ниже упрощенный пример.
что-то подсказывает что в конце в условии нужно правильно составить case...
правильный ли путь выбран?
что нужно "докрутить" чтоб работало?
declare @member_name nvarchar(10)
set @member_name = 'member2'

declare @member table (member_id int identity, member_role nvarchar(20), member_name nvarchar(10));

declare @doc table (doc_id int identity, memberA_id int, memberB_id int, memberC_id int)

insert into @member (member_role, member_name)
select 'roleA','member1' union all
select 'roleA','member2' union all
select 'roleB','member3' union all
select 'roleB','member4' union all
select 'roleC','member5' union all
select 'roleC','member6' union all
select 'roleA,roleB','member7'



--select * from @member

insert into @doc (memberA_id, memberB_id, memberC_id)
select 1,3,5    union all
select 2,3,null union all
select 1,3,5    union all
select 2,3,null union all
select 1,3,null union all
select 2,4,5    union all
select 1,4,null union all
select 2,4,null union all
select 1,4,6    union all
select 2,4,6    union all
select 1,4,null union all
select 2,4,null union all
select 1,3,6    union all
select 7,3,5    union all
select 1,7,5    union all
select 2,3,6 



-- таблицы "фильтра", сразу в них заполняем все, затем в зависимости от роли - исключаем
declare @filterA table (member_id int);insert @filterA select memberA_id from @doc group by memberA_id
declare @filterB table (member_id int);insert @filterB select memberB_id from @doc group by memberB_id
declare @filterC table (member_id int);insert @filterC select memberC_id from @doc group by memberC_id

declare @existRoleA bit; 
declare @existRoleB bit; 
declare @existRoleC bit; 

set @existRoleA = case when exists(select 1 from @member where member_name = @member_name and member_role like '%roleA%') then 1 else 0 end
set @existRoleB = case when exists(select 1 from @member where member_name = @member_name and member_role like '%roleB%') then 1 else 0 end
set @existRoleC = case when exists(select 1 from @member where member_name = @member_name and member_role like '%roleC%') then 1 else 0 end

if @existRoleA = 1 delete from @filterA where member_id not in (select member_id from @member where member_name = @member_name)

if @existRoleB = 1 delete from @filterB where member_id not in (select member_id from @member where member_name = @member_name)
    
if @existRoleC = 1 delete from @filterC where member_id not in (select member_id from @member where member_name = @member_name)        
    
-- если у member есть роль А - то то должны выбираться все документы где соответствующие memberA_id
--  memberC_id может быть null
-- если у member есть роль B - то то должны выбираться все документы где соответствующие memberB_id
--  memberC_id может быть null
-- если у member есть роль C - то то должны выбираться все документы где соответствующие memberC_id
--  memberC_id не может быть null

-- для удобства - слева исходная таблица доков - справа выборка согласно условиям
select d.*,'  -  ' as aaaaaaaaa , x.*
from @doc as d
left outer join
(
    select (select top 1 member_name+'/'+member_role from @member where member_name = @member_name )
      as member, d.* from @doc as d
    join @filterA as a on a.member_id = d.memberA_id
    join @filterB as b on b.member_id = d.memberB_id
    join @filterC as c on c.member_id = d.memberC_id
        --= case when @existRoleA = 1 or @existRoleB = 1 
        --    then null
        --    else d.memberC_id
        --  end
 ) as x on x.doc_id = d.doc_id
 
 
-- правильные наборы doc_id, для: 
-- member1/roleA - 1,3,5,7,9,11,13
-- member2/roleA - 2,4,6,8,10,12,16
-- member3/roleB - 1,2,3,4,5,13,14,16
-- member4/roleB - 6,7,8,9,10,11,12
-- member5/roleC - 1,3,6,14,15
-- member6/roleC - 9,10,13,16
-- member7/roleA,roleB - 14,15
3 апр 13, 12:28    [14130408]     Ответить | Цитировать Сообщить модератору
 Re: Подскажите с запросом )  [new]
Гость333
Member

Откуда:
Сообщений: 3683
Кифирчик
select 'roleA,roleB','member7'

"Первая нормальная форма? Не, не слышал"

Кифирчик
declare @doc table (doc_id int identity, memberA_id int, memberB_id int, memberC_id int)

Что будете делать, когда добавятся мемберы?

Кифирчик
declare @existRoleA bit; 
declare @existRoleB bit; 
declare @existRoleC bit; 

Аналогично — что будете делать, когда добавятся роли?

Кифирчик
правильный ли путь выбран?

нет

Кифирчик
что нужно "докрутить" чтоб работало?

Правильно спроектировать схему данных.
3 апр 13, 12:39    [14130500]     Ответить | Цитировать Сообщить модератору
 Re: Подскажите с запросом )  [new]
Кифирчик
Member

Откуда: СПб
Сообщений: 935
Оценил ваш сарказм с нормальной формой. А я то и не знал. Ха ха.
это упрощенная задача. я и упростил привязку ролей.

у документа фиксированное количество "мемберов" - 3, и меняться не будет

вообще количество мемберов может быть не ограниченным, и такая схема этому не противоречит. можете проверить.

количество ролей - фиксированное.

Кифирчик
правильный ли путь выбран?

нет
Кифирчик
что нужно "докрутить" чтоб работало?

Правильно спроектировать схему данных.

Ок. Ваше мнение понятно.
3 апр 13, 13:19    [14130839]     Ответить | Цитировать Сообщить модератору
 Re: Подскажите с запросом )  [new]
Гость333
Member

Откуда:
Сообщений: 3683
Кифирчик,

Ладно, фиг с ней, со структурой.

Я не очень понял:
1) для чего нужны таблицы-фильтры?

2) почему "правильные наборы doc_id, для: member1/roleA - 1,3,5,7,9,11,13" — по какому принципу нужно отсеять doc_id = 15?

3) вот такой запрос чем не подходит:
declare @member_id int;

select @member_id = m.member_id
from @member m
where m.member_name = @member_name

select d.*,'  -  ' as aaaaaaaaa , x.*
from @doc as d
left outer join
(
    select (select top 1 member_name+'/'+member_role from @member where member_name = @member_name )
      as member, d.*
    from @doc as d
    where d.memberA_id = @member_id or d.memberB_id = @member_id or d.memberC_id = @member_id
 ) as x on x.doc_id = d.doc_id
3 апр 13, 13:53    [14131082]     Ответить | Цитировать Сообщить модератору
 Re: Подскажите с запросом )  [new]
Кифирчик
Member

Откуда: СПб
Сообщений: 935
Ах ха ха! ))))
действительно )))
>2) почему "правильные наборы doc_id, для: member1/roleA - 1,3,5,7,9,11,13"
> — по какому принципу нужно отсеять doc_id = 15?
Вы правы... 15й номер должен присутствовать.

и Ваш запрос действительно работает как нужно ))))

Спасибо )

Я что-то совсем заработался ))))
3 апр 13, 14:11    [14131194]     Ответить | Цитировать Сообщить модератору
Все форумы / Microsoft SQL Server Ответить