SQL Server: использование существует в таблице, используемой в соединении - PullRequest
0 голосов
/ 18 октября 2018

Предположим, у меня есть таблица WorkItems, в которой есть рабочие элементы, их статус и описание.Есть еще две таблицы Persons и WorkItemPersonLinks, в которых содержатся данные о лицах, которым назначены рабочие элементы, и данные о том, какой элемент назначен тому или иному человеку соответственно.Схема выглядит примерно так -

Create table WorkItems 
(
    Id int not null primary key,
    Description varchar (100),
    Status varchar (30),
    IfValid bit not null,
)

Create table Persons
(
    Id int not null primary key,
    Name varchar (100),
    IfValid bit not null
)

Create table WorkItemPersonLinks
(
    Id int not null primary key,
    WorkItemId int foreign key references WorkItems(Id),
    PersonId int foreign key references Persons(Id),
    IfValid bit not null
)

Вот некоторые примеры данных -

insert into workItems values
(1, 'Go Fishing', 'To do', 1), 
(2, 'Play video game', 'Done', 1), 
(3, 'Cook Dinner', 'In progress', 1), 
(4, 'Purchase Groceries', 'Done', 1)

insert into Persons values
(1, 'Tom', 1), (2, 'Dick', 1), (3, 'Harry', 1)    

insert into WorkItemPersonLinks values
(1, 1, 1, 1), (2, 2, 2, 1), (3, 3, 3, 1), (4, 4, 2, 1),
(5, 2, 1, 1), (6, 3, 2, 1), (7, 3, 1, 1), (8, 4, 3, 1)

Вот что я хочу, предположим, у меня есть входной параметр @viewOption, который может принимать возможные значенияmy (только мои рабочие элементы), done (все готовые элементы), not done (рабочие элементы с Status <> 'done') и all (все рабочие элементы) и другой параметр @userId, который может иметьЗначение int может быть любым из таблицы Persons.Итак, предположим, что пользователь (Том) хочет видеть только his задач, в этом случае @viewOption = 'my' и @userId = 1 (Идентификатор Тома в таблице Persons.

ОБНОВЛЕНИЕ

Один рабочий элемент может быть назначен нескольким лицам, поэтому даже если для @viewOption установлено значение my, запрос должен возвращать данные других лиц, назначенных этому элементу (кроме пользователя), ине только его собственные данные.

Запрос, с которым мне тяжело работать, как показано ниже -

declare @viewOption varchar(10) = 'my'
declare @userId int = 1

select p.Name, wi.Description, wi.status from WorkItems wi
inner join WorkItemPersonLinks wpl on wi.Id = wpl.WorkItemId 
inner join Persons p on wpl.PersonId = p.Id
where wi.IfValid = 1 and wpl.IfValid = 1 and p.IfValid = 1 and ((@viewOption = 'my' and exists(select 1 from wpl where wpl.PersonId = @userId))
   or (@viewOption = 'all')
   or (@viewOption = 'done' and wi.Status = 'done')
   or (@viewOption = 'not done' and wi.Status <> 'done'))

Есть эта ошибка Invalid object name 'wpl, которая, как я понимаю, возникает из-за контекстаиз условия exists, где оно недопустимо. Я могу заставить это работать, используя операторы case над @viewOption, но хотел дважды проверить лучший (и более элегантный) способ сделать это, прежде чем я сделаю запрос.

Ответы [ 3 ]

0 голосов
/ 18 октября 2018

Вам нужно использовать имя таблицы там, а не локальный псевдоним выше, а также сделать ссылку на рабочий элемент:

select p.Name, wi.Description, wi.status 
from WorkItems wi
inner join WorkItemPersonLinks wpl on wi.Id = wpl.WorkItemId 
inner join Persons p on wpl.PersonId = p.Id
where wi.IfValid = 1 and wpl.IfValid = 1 and p.IfValid = 1 and 
   ((@viewOption = 'my' and exists 
     (select * from WorkItemPersonLinks w2 
      where w2.WorkItemId = wi.Id and w2.PersonId = @userId))
   or (@viewOption = 'all')
   or (@viewOption = 'done' and wi.Status = 'done')
   or (@viewOption = 'not done' and wi.Status <> 'done'));
0 голосов
/ 18 октября 2018

Пожалуйста, попробуйте это:

select p.name
    ,wi.description
    ,wi.status
from workitems wi
inner join workitempersonlinks wpl on wi.id = wpl.workitemid
inner join persons p on wpl.personid = p.id
where wi.ifvalid = 1
    and wpl.ifvalid = 1
    and p.ifvalid = 1
    and (
            (@viewoption = 'my' and wi.id in (select [WorkItemId] from  workitempersonlinks where PersonId =  @userid))
        or  (@viewoption = 'all')
        or  (@viewoption = 'done' and wi.status = 'done')
        or  (@viewoption = 'not done' and wi.status <> 'done')
    )
0 голосов
/ 18 октября 2018

Будет ли работать ниже?Если я правильно понял, вы хотите увидеть результаты запроса, если переданный идентификатор пользователя существует в поисковом запросе (где ViewOption - «Мой»).Я сделал это, используя операторы IF, чтобы выбрать лучший запрос для выполнения, надеюсь, он будет работать для вас

declare @viewOption varchar(10) = 'my'
declare @userId int = 1

IF @viewOption = 'my' AND @userid IN (
    SELECT DISTINCT
        wpl.PersonId
    FROM
        WorkItems wi
        inner join WorkItemPersonLinks wpl on wi.Id = wpl.WorkItemId 
        inner join Persons p on wpl.PersonId = p.Id)
BEGIN
    SELECT
        p.Name,
        wi.Description,
        wi.status
    FROM
        WorkItems wi
        INNER JOIN WorkItemPersonLinks wpl on wi.Id = wpl.WorkItemId 
        INNER JOIN Persons p on wpl.PersonId = p.Id
    WHERE
        wi.IfValid = 1
        AND wpl.IfValid = 1
        AND p.IfValid = 1
END

IF @viewOption IN ('all', 'done', 'not done')
BEGIN
    SELECT
        p.Name,
        wi.Description,
        wi.status
    FROM
        WorkItems wi
        INNER JOIN WorkItemPersonLinks wpl ON wi.Id = wpl.WorkItemId 
        INNER JOIN Persons p ON wpl.PersonId = p.Id
    WHERE
        (@viewOption = 'all')
       OR (@viewOption = 'done' AND wi.Status = 'done')
       OR (@viewOption = 'not done' AND wi.Status <> 'done')
END
...